Merge "Binderized GPS - restoring Xtra service"
diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h
index 63ea1bb..b49e658 100644
--- a/audio/2.0/default/Stream.h
+++ b/audio/2.0/default/Stream.h
@@ -146,7 +146,6 @@
     }
     _hidl_cb(retval, info);
     if (hidlHandle != nullptr) {
-        native_handle_close(hidlHandle);
         native_handle_delete(hidlHandle);
     }
     return Void();
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
index cdc8ded..6ccdbcd 100644
--- a/audio/2.0/default/StreamOut.cpp
+++ b/audio/2.0/default/StreamOut.cpp
@@ -79,10 +79,6 @@
         ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
         if (writeResult >= 0) {
             mStatus.reply.written = writeResult;
-            // Diagnostics of the cause of b/35813113.
-            ALOGE_IF(writeResult > availToRead,
-                    "legacy hal reports more bytes written than asked for: %lld > %lld",
-                    (long long)writeResult, (long long)availToRead);
         } else {
             mStatus.retval = Stream::analyzeStatus("write", writeResult);
         }
diff --git a/audio/2.0/vts/functional/Android.bp b/audio/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..05b1817
--- /dev/null
+++ b/audio/2.0/vts/functional/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalAudioV2_0TargetTest",
+    gtest: true,
+    srcs: ["AudioPrimaryHidlHalTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libhidlbase",
+        "libutils",
+        "libcutils",
+        "android.hardware.audio@2.0",
+        "android.hardware.audio.common@2.0",
+    ],
+    static_libs: ["libgtest"],
+    cflags: [
+        "-O0",
+        "-g",
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
diff --git a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..cc20456
--- /dev/null
+++ b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,708 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalAudioV2_0TargetTest"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdio>
+#include <limits>
+#include <list>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include <android/hardware/audio/2.0/IDevice.h>
+#include <android/hardware/audio/2.0/IDevicesFactory.h>
+#include <android/hardware/audio/2.0/types.h>
+#include <android/hardware/audio/common/2.0/types.h>
+
+#include "utility/ReturnIn.h"
+#include "utility/AssertOk.h"
+#include "utility/PrettyPrintAudioTypes.h"
+
+using std::string;
+using std::to_string;
+using std::vector;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::IDevicesFactory;
+using ::android::hardware::audio::V2_0::IStream;
+using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioConfig;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::common::V2_0::AudioHandleConsts;
+using ::android::hardware::audio::common::V2_0::AudioInputFlag;
+using ::android::hardware::audio::common::V2_0::AudioIoHandle;
+using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
+using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+
+using utility::returnIn;
+
+namespace doc {
+/** Document the current test case.
+ * Eg: calling `doc::test("Dump the state of the hal")` in the "debugDump" test will output:
+ *   <testcase name="debugDump" status="run" time="6" classname="AudioPrimaryHidlTest"
+            description="Dump the state of the hal." />
+ * see https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#logging-additional-information
+ */
+void test(const std::string& testCaseDocumentation) {
+    ::testing::Test::RecordProperty("description", testCaseDocumentation);
+}
+
+/** Document why a test was not fully run. Usually due to an optional feature not implemented. */
+void partialTest(const std::string& reason) {
+    ::testing::Test::RecordProperty("partialyRunTest", reason);
+}
+}
+
+// Register callback for static object destruction
+// Avoid destroying static objects after main return.
+// Post main return destruction leads to incorrect gtest timing measurements as well as harder
+// debuging if anything goes wrong during destruction.
+class Environment : public ::testing::Environment {
+public:
+    using TearDownFunc = std::function<void ()>;
+     void registerTearDown(TearDownFunc&& tearDown) {
+         tearDowns.push_back(std::move(tearDown));
+    }
+
+private:
+    void TearDown() override {
+        // Call the tear downs in reverse order of insertion
+        for (auto& tearDown : tearDowns) {
+            tearDown();
+        }
+    }
+    std::list<TearDownFunc> tearDowns;
+};
+// Instance to register global tearDown
+static Environment* environment;
+
+class HidlTest : public ::testing::Test {
+protected:
+    // Convenient member to store results
+    Result res;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////// getService audio_devices_factory //////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test all audio devices
+class AudioHidlTest : public HidlTest {
+public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base
+
+        if (devicesFactory == nullptr) {
+            environment->registerTearDown([]{ devicesFactory.clear(); });
+            devicesFactory = IDevicesFactory::getService();
+        }
+        ASSERT_TRUE(devicesFactory != nullptr);
+    }
+
+protected:
+    // Cache the devicesFactory retrieval to speed up each test by ~0.5s
+    static sp<IDevicesFactory> devicesFactory;
+};
+sp<IDevicesFactory> AudioHidlTest::devicesFactory;
+
+TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
+    doc::test("test the getService (called in SetUp)");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// openDevice primary ///////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test the primary device
+class AudioPrimaryHidlTest : public AudioHidlTest {
+public:
+    /** Primary HAL test are NOT thread safe. */
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base
+
+        if (device == nullptr) {
+            environment->registerTearDown([]{ device.clear(); });
+            IDevicesFactory::Result result;
+            ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
+                                                 returnIn(result, device)));
+        }
+        ASSERT_TRUE(device != nullptr);
+    }
+
+protected:
+    // Cache the device opening to speed up each test by ~0.5s
+    static sp<IDevice> device;
+};
+sp<IDevice> AudioPrimaryHidlTest::device;
+
+TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+    doc::test("Test the openDevice (called in SetUp)");
+}
+
+TEST_F(AudioPrimaryHidlTest, Init) {
+    doc::test("Test that the audio primary hal initialized correctly");
+    ASSERT_OK(device->initCheck());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////// {set,get}MasterVolume ///////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class MasterVolumeTest : public AudioPrimaryHidlTest {
+protected:
+    void testSetGetConsistency(float volume, Result expectedSetResult, float expectedGetVolume) {
+        SCOPED_TRACE("Test set/get consistency for " + to_string(volume));
+        auto ret = device->setMasterVolume(volume);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(expectedSetResult, ret);
+
+        float observedVolume;
+        ASSERT_OK(device->getMasterVolume(returnIn(res, observedVolume)));
+        ASSERT_OK(res);
+
+        // Check that `get` returned the expected value
+        EXPECT_EQ(expectedGetVolume, observedVolume);
+    }
+};
+
+TEST_F(MasterVolumeTest, MasterVolumeTest) {
+    doc::test("Test the master volume if supported");
+    {
+        SCOPED_TRACE("Check for master volume support");
+        auto ret = device->setMasterVolume(1);
+        ASSERT_TRUE(ret.isOk());
+        if (ret == Result::NOT_SUPPORTED) {
+            doc::partialTest("Master volume is not supported");
+            return;
+        }
+    }
+    // NOTE: this code has never been tested on a platform supporting MasterVolume
+    float lastValidVolumeSet;
+    using Volumes = float[];
+    SCOPED_TRACE("As set/get master volume are supported...");
+    {
+        SCOPED_TRACE("...test them with valid values");
+        for (float validVolume : Volumes{0, 0.5, 1}) {
+            ASSERT_NO_FATAL_FAILURE(testSetGetConsistency(validVolume, Result::OK, validVolume));
+            lastValidVolumeSet = validVolume;
+        }
+    }{
+        SCOPED_TRACE("...test them with tricky values");
+        for (float outOfBoundVolume :Volumes{-0.1, 1.1, NAN, INFINITY, -INFINITY,
+                                             1 + std::numeric_limits<float>::epsilon()}) {
+        ASSERT_NO_FATAL_FAILURE(testSetGetConsistency(outOfBoundVolume,
+                                                      Result::INVALID_ARGUMENTS,
+                                                      lastValidVolumeSet));
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////// {set,get}{Master,Mic}Mute /////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class BoolAccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
+protected:
+    template <class Getter, class Setter>
+    void testBoolAccessors(const string& propertyName, const vector<bool>& valuesToTest,
+                           Setter setter, Getter getter) {
+        for (bool setState : valuesToTest) {
+            SCOPED_TRACE("Test " + propertyName + " state: " + to_string(setState));
+            ASSERT_OK((device.get()->*setter)(setState));
+            bool getState;
+            ASSERT_OK((device.get()->*getter)(returnIn(res, getState)));
+            ASSERT_OK(res);
+            ASSERT_EQ(setState, getState);
+        }
+    }
+};
+
+TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+    doc::test("Check that the mic can be muted and unmuted");
+    testBoolAccessors("mic mute", {true, false, true}, &IDevice::setMicMute, &IDevice::getMicMute);
+    // TODO: check that the mic is really muted (all sample are 0)
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
+    doc::test("If master mute is supported, try to mute and unmute the master output");
+    {
+        SCOPED_TRACE("Check for master mute support");
+        auto ret = device->setMasterMute(false);
+        ASSERT_TRUE(ret.isOk());
+        if (ret == Result::NOT_SUPPORTED) {
+            doc::partialTest("Master mute is not supported");
+            return;
+        }
+    }
+    // NOTE: this code has never been tested on a platform supporting MasterMute
+    testBoolAccessors("master mute", {true, false, true},
+                      &IDevice::setMasterMute, &IDevice::getMasterMute);
+    // TODO: check that the master volume is really muted
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////// Required and recommended audio format support ///////////////
+// From: https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
+// From: https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback
+/////////// TODO: move to the beginning of the file for easier update ////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioConfigPrimaryTest : public AudioPrimaryHidlTest {
+public:
+    // Cache result ?
+    static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+                                  {8000, 11025, 16000, 22050, 32000, 44100},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+
+    static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+                                  {24000, 48000},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+
+    static const vector<AudioConfig> getSupportedPlaybackAudioConfig() {
+        // TODO: retrieve audio config supported by the platform
+        // as declared in the policy configuration
+        return {};
+    }
+
+    static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::IN_MONO},
+                                  {8000, 11025, 16000, 44100},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+    static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::IN_STEREO},
+                                  {22050, 48000},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+    static const vector<AudioConfig> getSupportedCaptureAudioConfig() {
+        // TODO: retrieve audio config supported by the platform
+        // as declared in the policy configuration
+        return {};
+    }
+private:
+    static const vector<AudioConfig> combineAudioConfig(
+            vector<AudioChannelMask> channelMasks,
+            vector<uint32_t> sampleRates,
+            vector<AudioFormat> formats) {
+        vector<AudioConfig> configs;
+        for (auto channelMask: channelMasks) {
+            for (auto sampleRate : sampleRates) {
+                for (auto format : formats) {
+                    AudioConfig config{};
+                    // leave offloadInfo to 0
+                    config.channelMask = channelMask;
+                    config.sampleRateHz = sampleRate;
+                    config.format = format;
+                    // FIXME: leave frameCount to 0 ?
+                    configs.push_back(config);
+                }
+            }
+        }
+        return configs;
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////// getInputBufferSize /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// FIXME: execute input test only if platform declares android.hardware.microphone
+//        how to get this value ? is it a property ???
+
+class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
+                                      public ::testing::WithParamInterface<AudioConfig> {
+protected:
+    void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
+        uint64_t bufferSize;
+        ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+
+        switch (res) {
+            case Result::INVALID_ARGUMENTS:
+                EXPECT_FALSE(supportRequired);
+                break;
+            case Result::OK:
+                // Check that the buffer is of a sane size
+                // For now only that it is > 0
+                EXPECT_GT(bufferSize, uint64_t(0));
+                break;
+            default:
+                FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+        }
+    }
+};
+
+// Test that the required capture config and those declared in the policy are indeed supported
+class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) {
+    doc::test("Input buffer size must be retrievable for a format with required support.");
+    inputBufferSizeTest(GetParam(), true);
+}
+INSTANTIATE_TEST_CASE_P(
+        RequiredInputBufferSize, RequiredInputBufferSizeTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()));
+INSTANTIATE_TEST_CASE_P(
+        SupportedInputBufferSize, RequiredInputBufferSizeTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()));
+
+// Test that the recommended capture config are supported or lead to a INVALID_ARGUMENTS return
+class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) {
+    doc::test("Input buffer size should be retrievable for a format with recommended support.");
+    inputBufferSizeTest(GetParam(), false);
+}
+INSTANTIATE_TEST_CASE_P(
+        RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()));
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// setScreenState ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, setScreenState) {
+    doc::test("Check that the hal can receive the screen state");
+    for (bool turnedOn : {false, true, true, false, false}) {
+        auto ret = device->setScreenState(turnedOn);
+        ASSERT_TRUE(ret.isOk());
+        Result result = ret;
+        ASSERT_TRUE(result == Result::OK || result == Result::NOT_SUPPORTED) << toString(result);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////// {get,set}Parameters /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, getParameters) {
+    doc::test("Check that the hal can set and get parameters");
+    hidl_vec<hidl_string> keys;
+    hidl_vec<ParameterValue> values;
+    ASSERT_OK(device->getParameters(keys, returnIn(res, values)));
+    ASSERT_OK(device->setParameters(values));
+    values.resize(0);
+    ASSERT_OK(device->setParameters(values));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// debugDebug //////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, debugDump) {
+    doc::test("Check that the hal can dump its state without error");
+    FILE* file = tmpfile();
+    ASSERT_NE(nullptr, file) << errno;
+
+    auto* nativeHandle = native_handle_create(1, 0);
+    ASSERT_NE(nullptr, nativeHandle);
+    nativeHandle->data[0] = fileno(file);
+
+    hidl_handle handle;
+    handle.setTo(nativeHandle, true /*take ownership*/);
+
+    auto ret = device->debugDump(handle);
+    ASSERT_TRUE(ret.isOk());
+
+    // FIXME: debugDump does not return a Result.
+    // This mean that the hal can not report that it not implementing the function.
+    // As the default hal does not implement debugDump, the function can not be tested.
+    /*
+    res = ret;
+    if (res == Result::NOT_SUPPORTED) {
+         doc::partialTest("debugDump is not implemented");
+         return;
+    }
+    ASSERT_OK(res);
+    rewind(file);
+
+    // Check that at least one bit was written by the hal
+    char buff;
+    ASSERT_EQ(1, fread(&buff, sizeof(buff), 1, file));
+    */
+    EXPECT_EQ(0, fclose(file)) << errno;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////// open{Output,Input}Stream //////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class Stream>
+class OpenStreamTest : public AudioConfigPrimaryTest,
+                       public ::testing::WithParamInterface<AudioConfig> {
+protected:
+    template <class Open>
+    void testOpen(Open openStream, const AudioConfig& config) {
+        // FIXME: Open a stream without an IOHandle
+        //        This is not required to be accepted by hal implementations
+        AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
+        AudioConfig suggestedConfig{};
+        ASSERT_OK(openStream(ioHandle, config, returnIn(res, stream, suggestedConfig)));
+
+        // TODO: only allow failure for RecommendedPlaybackAudioConfig
+        switch (res) {
+            case Result::OK:
+                ASSERT_TRUE(stream != nullptr);
+                audioConfig = config;
+                break;
+            case Result::INVALID_ARGUMENTS:
+                ASSERT_TRUE(stream == nullptr);
+                AudioConfig suggestedConfigRetry;
+                // Could not open stream with config, try again with the suggested one
+                ASSERT_OK(openStream(ioHandle, suggestedConfig,
+                                     returnIn(res, stream, suggestedConfigRetry)));
+                // This time it must succeed
+                ASSERT_OK(res);
+                ASSERT_TRUE(stream == nullptr);
+                audioConfig = suggestedConfig;
+                break;
+            default:
+                FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+        }
+        open = true;
+    }
+
+private:
+    void TearDown() override {
+        if (open) {
+            ASSERT_OK(stream->close());
+        }
+    }
+
+protected:
+
+    AudioConfig audioConfig;
+    sp<Stream> stream;
+    bool open = false;
+};
+
+////////////////////////////// openOutputStream //////////////////////////////
+
+class OutputStreamTest : public OpenStreamTest<IStreamOut> {
+    virtual void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+
+        const AudioConfig& config = GetParam();
+        DeviceAddress deviceAddr{};  // Ignored by primary hal
+        AudioOutputFlag flags = AudioOutputFlag::NONE; // TODO: test all flag combination
+        testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
+                 { return device->openOutputStream(handle, deviceAddr, config, flags, cb); },
+                 config);
+    }
+};
+TEST_P(OutputStreamTest, OpenOutputStreamTest) {
+    doc::test("Check that output streams can be open with the required and recommended config");
+    // Open done in SetUp
+}
+INSTANTIATE_TEST_CASE_P(
+        RequiredOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()));
+INSTANTIATE_TEST_CASE_P(
+        SupportedOutputStreamConfig, OutputStreamTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()));
+
+INSTANTIATE_TEST_CASE_P(
+        RecommendedOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()));
+
+////////////////////////////// openInputStream //////////////////////////////
+
+class InputStreamTest : public OpenStreamTest<IStreamIn> {
+
+    virtual void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+
+        const AudioConfig& config = GetParam();
+        DeviceAddress deviceAddr{}; // TODO: test all devices
+        AudioInputFlag flags = AudioInputFlag::NONE; // TODO: test all flag combination
+        AudioSource source = AudioSource::DEFAULT; // TODO: test all flag combination
+        testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
+                 { return device->openInputStream(handle, deviceAddr, config, flags, source, cb); },
+                 config);
+    }
+};
+
+TEST_P(InputStreamTest, OpenInputStreamTest) {
+    doc::test("Check that input streams can be open with the required and recommended config");
+    // Open done in setup
+}
+INSTANTIATE_TEST_CASE_P(
+        RequiredInputStreamConfigSupport, InputStreamTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()));
+INSTANTIATE_TEST_CASE_P(
+        SupportedInputStreamConfig, InputStreamTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()));
+
+INSTANTIATE_TEST_CASE_P(
+        RecommendedInputStreamConfigSupport, InputStreamTest,
+        ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()));
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// IStream getters ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+/** Unpack the provided result.
+ * If the result is not OK, register a failure and return an undefined value. */
+template <class R>
+static R extract(Return<R> ret) {
+    if (!ret.isOk()) {
+        ADD_FAILURE();
+        return R{};
+    }
+    return ret;
+}
+
+template <class Property, class CapabilityGetter, class Getter, class Setter>
+static void testCapabilityGetter(const string& name,IStream* stream, Property currentValue,
+                                 CapabilityGetter capablityGetter, Getter getter, Setter setter) {
+    hidl_vec<Property> capabilities;
+    ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities)));
+    if (capabilities.size() == 0) {
+        // The default hal should probably return a NOT_SUPPORTED if the hal does not expose
+        // capability retrieval. For now it returns an empty list if not implemented
+        doc::partialTest(name + " is not supported");
+        return;
+    };
+    // TODO: This code has never been tested on a hal that supports getSupportedSampleRates
+    EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue),
+             capabilities.end())
+        << "current " << name << " is not in the list of the supported ones "
+        << toString(capabilities);
+
+    // Check that all declared supported values are indeed supported
+    for (auto capability : capabilities) {
+        ASSERT_OK((stream->*setter)(capability));
+        ASSERT_EQ(capability, extract((stream->*getter)()));
+    }
+}
+
+static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
+    uint32_t sampleRateHz;
+    AudioChannelMask mask;
+    AudioFormat format;
+
+    stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+
+    // FIXME: the qcom hal it does not currently negotiate the sampleRate & channel mask
+    // EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz);
+    // EXPECT_EQ(expectedConfig.channelMask, mask);
+    EXPECT_EQ(expectedConfig.format, format);
+}
+
+static void testAccessors(IStream* stream, AudioConfig audioConfig) {
+    doc::test("Test IStream getters and setters that can be called in the stop state");
+
+    auto frameCount = extract(stream->getFrameCount());
+    ASSERT_EQ(audioConfig.frameCount, frameCount);
+
+    auto sampleRate = extract(stream->getSampleRate());
+    // FIXME: the qcom hal it does not currently negotiate the sampleRate
+    // ASSERT_EQ(audioConfig.sampleRateHz, sampleRate);
+
+    auto channelMask = extract(stream->getChannelMask());
+    // FIXME: the qcom hal it does not currently negotiate the channelMask
+    // ASSERT_EQ(audioConfig.channelMask, channelMask);
+
+    auto frameSize = extract(stream->getFrameSize());
+    ASSERT_GE(frameSize, 0U);
+
+    auto bufferSize = extract(stream->getBufferSize());
+    ASSERT_GE(bufferSize, frameSize);
+
+    testCapabilityGetter("getSupportedsampleRate", stream, sampleRate,
+                         &IStream::getSupportedSampleRates,
+                         &IStream::getSampleRate, &IStream::setSampleRate);
+
+    testCapabilityGetter("getSupportedChannelMask", stream, channelMask,
+                         &IStream::getSupportedChannelMasks,
+                         &IStream::getChannelMask, &IStream::setChannelMask);
+
+    AudioFormat format = extract(stream->getFormat());
+    ASSERT_EQ(audioConfig.format, format);
+
+    testCapabilityGetter("getSupportedFormats", stream, format,
+                         &IStream::getSupportedFormats, &IStream::getFormat, &IStream::setFormat);
+
+    testGetAudioProperties(stream, audioConfig);
+
+    // FIXME: Stream wrapper does not implement getDevice properly.
+    // It needs to call getProperty({"routing"}).
+    // The current implementation segfault with the default hal
+    /*
+     * auto ret = stream->getDevice();
+     * ASSERT_TRUE(ret.isOk());
+     * AudioDevice device = ret;
+     * ASSERT_EQ(AudioDevice::OUT_ALL, device);
+     */
+}
+
+TEST_P(InputStreamTest, GettersTest) {
+    testAccessors(stream.get(), audioConfig);
+}
+TEST_P(OutputStreamTest, GettersTest) {
+    testAccessors(stream.get(), audioConfig);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// AudioPatches ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+
+TEST_F(AudioPrimaryHidlTest, AudioPatches) {
+    doc::test("Test if audio patches are supported");
+    auto result = device->supportsAudioPatches();
+    ASSERT_TRUE(result.isOk());
+    bool supportsAudioPatch = result;
+    if (!supportsAudioPatch) {
+        doc::partialTest("Audio patches are not supported");
+        return;
+    }
+    // TODO: test audio patches
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////// Clean caches on global tear down ////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char** argv) {
+    environment = new Environment;
+    ::testing::AddGlobalTestEnvironment(environment);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/audio/2.0/vts/functional/utility/AssertOk.h b/audio/2.0/vts/functional/utility/AssertOk.h
new file mode 100644
index 0000000..5397436
--- /dev/null
+++ b/audio/2.0/vts/functional/utility/AssertOk.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <hidl/Status.h>
+
+namespace detail {
+
+inline void assertOk(::android::hardware::Return<void> ret) {
+    ASSERT_TRUE(ret.isOk());
+}
+
+inline void assertOk(::android::hardware::audio::V2_0::Result result) {
+    ASSERT_EQ(decltype(result)::OK, result);
+}
+
+inline void assertOk(::android::hardware::Return<::android::hardware::audio::V2_0::Result> ret) {
+    ASSERT_TRUE(ret.isOk());
+    ::android::hardware::audio::V2_0::Result result = ret;
+    assertOk(result);
+}
+
+}
+
+// Test anything provided is and contains only OK
+#define ASSERT_OK(ret) ASSERT_NO_FATAL_FAILURE(detail::assertOk(ret))
+#define EXPECT_OK(ret) EXPECT_NO_FATAL_FAILURE(detail::assertOk(ret))
diff --git a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
new file mode 100644
index 0000000..8dfcb29
--- /dev/null
+++ b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Use HIDL generated toString methods to pretty print gtest errors
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+inline void PrintTo(const Result& result, ::std::ostream* os) {
+    *os << toString(result);
+}
+} // namespace V2_0
+namespace common {
+namespace V2_0 {
+inline void PrintTo(const AudioConfig& config, ::std::ostream* os) {
+    *os << toString(config);
+}
+} // namespace V2_0
+} // namespace common
+}
+}
+}
diff --git a/audio/2.0/vts/functional/utility/ReturnIn.h b/audio/2.0/vts/functional/utility/ReturnIn.h
new file mode 100644
index 0000000..bb2389a
--- /dev/null
+++ b/audio/2.0/vts/functional/utility/ReturnIn.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <tuple>
+
+namespace utility {
+
+namespace detail {
+// Helper class to generate the HIDL synchronous callback
+template <class... ResultStore>
+class ReturnIn {
+ public:
+    // Provide to the constructor the variables where the output parameters must be copied
+    // TODO: take pointers to match google output parameter style ?
+    ReturnIn(ResultStore&... ts) : results(ts...) {}
+    // Synchronous callback
+    template <class... Results>
+    void operator() (Results&&...results) {
+        set(std::forward<Results>(results)...);
+    }
+ private:
+    // Recursively set all output parameters
+    template <class Head, class... Tail>
+    void set(Head&& head, Tail&&... tail) {
+        std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results)
+                  = std::forward<Head>(head);
+        set(tail...);
+    }
+    // Trivial case
+    void set() {}
+
+    // All variables to set are stored here
+    std::tuple<ResultStore&...> results;
+};
+} // namespace detail
+
+// Generate the HIDL synchronous callback with a copy policy
+// Input: the variables (lvalue reference) where to save the return values
+// Output: the callback to provide to a HIDL call with a synchronous callback
+// The output parameters *will be copied* do not use this function if you have
+// a zero copy policy
+template <class... ResultStore>
+detail::ReturnIn<ResultStore...> returnIn(ResultStore&... ts) { return {ts...};}
+
+}
diff --git a/audio/Android.bp b/audio/Android.bp
index 3121a36..8a1e892 100644
--- a/audio/Android.bp
+++ b/audio/Android.bp
@@ -1,6 +1,7 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
     "2.0",
+    "2.0/vts/functional",
     "common/2.0",
     "effect/2.0",
     "effect/2.0/vts/functional",
diff --git a/audio/common/2.0/types.hal b/audio/common/2.0/types.hal
index ae7f545..93b898b 100644
--- a/audio/common/2.0/types.hal
+++ b/audio/common/2.0/types.hal
@@ -537,6 +537,7 @@
     /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
     OUT_BUS                       = 0x1000000,
     OUT_PROXY                     = 0x2000000,
+    OUT_USB_HEADSET               = 0x4000000,
     OUT_DEFAULT                   = BIT_DEFAULT,
     OUT_ALL      = (OUT_EARPIECE |
             OUT_SPEAKER |
@@ -603,6 +604,7 @@
     /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
     IN_BUS                   = BIT_IN | 0x100000,
     IN_PROXY                 = BIT_IN | 0x1000000,
+    IN_USB_HEADSET           = BIT_IN | 0x2000000,
     IN_DEFAULT               = BIT_IN | BIT_DEFAULT,
 
     IN_ALL     = (IN_COMMUNICATION |
@@ -670,6 +672,7 @@
     DIRECT_PCM = 0x2000,     // Audio stream containing PCM data that needs
                              // to pass through compress path for DSP post proc.
     MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+    VOIP_CALL_RX = 0x8000, // preferred output for VoIP calls.
 };
 
 /*
@@ -680,12 +683,13 @@
  */
 @export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
 enum AudioInputFlag : int32_t {
-    NONE       = 0x0,  // no attributes
-    FAST       = 0x1,  // prefer an input that supports "fast tracks"
-    HW_HOTWORD = 0x2,  // prefer an input that captures from hw hotword source
-    RAW        = 0x4,  // minimize signal processing
-    SYNC       = 0x8,  // synchronize I/O streams
-    MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
+    NONE         = 0x0,  // no attributes
+    FAST         = 0x1,  // prefer an input that supports "fast tracks"
+    HW_HOTWORD   = 0x2,  // prefer an input that captures from hw hotword source
+    RAW          = 0x4,  // minimize signal processing
+    SYNC         = 0x8,  // synchronize I/O streams
+    MMAP_NOIRQ   = 0x10, // input operates in MMAP no IRQ mode.
+    VOIP_CALL_TX = 0x20, // preferred input for VoIP calls.
 };
 
 @export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
diff --git a/automotive/Android.bp b/automotive/Android.bp
index 1f39e88..9b24ded 100644
--- a/automotive/Android.bp
+++ b/automotive/Android.bp
@@ -1,5 +1,7 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
+    "evs/1.0",
+    "evs/1.0/default",
     "vehicle/2.0",
     "vehicle/2.1",
 ]
diff --git a/automotive/evs/1.0/Android.bp b/automotive/evs/1.0/Android.bp
new file mode 100644
index 0000000..042becd
--- /dev/null
+++ b/automotive/evs/1.0/Android.bp
@@ -0,0 +1,83 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+    name: "android.hardware.automotive.evs@1.0_hal",
+    srcs: [
+        "types.hal",
+        "IEvsCamera.hal",
+        "IEvsCameraStream.hal",
+        "IEvsDisplay.hal",
+        "IEvsEnumerator.hal",
+    ],
+}
+
+genrule {
+    name: "android.hardware.automotive.evs@1.0_genc++",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.evs@1.0",
+    srcs: [
+        ":android.hardware.automotive.evs@1.0_hal",
+    ],
+    out: [
+        "android/hardware/automotive/evs/1.0/types.cpp",
+        "android/hardware/automotive/evs/1.0/EvsCameraAll.cpp",
+        "android/hardware/automotive/evs/1.0/EvsCameraStreamAll.cpp",
+        "android/hardware/automotive/evs/1.0/EvsDisplayAll.cpp",
+        "android/hardware/automotive/evs/1.0/EvsEnumeratorAll.cpp",
+    ],
+}
+
+genrule {
+    name: "android.hardware.automotive.evs@1.0_genc++_headers",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.evs@1.0",
+    srcs: [
+        ":android.hardware.automotive.evs@1.0_hal",
+    ],
+    out: [
+        "android/hardware/automotive/evs/1.0/types.h",
+        "android/hardware/automotive/evs/1.0/IEvsCamera.h",
+        "android/hardware/automotive/evs/1.0/IHwEvsCamera.h",
+        "android/hardware/automotive/evs/1.0/BnHwEvsCamera.h",
+        "android/hardware/automotive/evs/1.0/BpHwEvsCamera.h",
+        "android/hardware/automotive/evs/1.0/BsEvsCamera.h",
+        "android/hardware/automotive/evs/1.0/IEvsCameraStream.h",
+        "android/hardware/automotive/evs/1.0/IHwEvsCameraStream.h",
+        "android/hardware/automotive/evs/1.0/BnHwEvsCameraStream.h",
+        "android/hardware/automotive/evs/1.0/BpHwEvsCameraStream.h",
+        "android/hardware/automotive/evs/1.0/BsEvsCameraStream.h",
+        "android/hardware/automotive/evs/1.0/IEvsDisplay.h",
+        "android/hardware/automotive/evs/1.0/IHwEvsDisplay.h",
+        "android/hardware/automotive/evs/1.0/BnHwEvsDisplay.h",
+        "android/hardware/automotive/evs/1.0/BpHwEvsDisplay.h",
+        "android/hardware/automotive/evs/1.0/BsEvsDisplay.h",
+        "android/hardware/automotive/evs/1.0/IEvsEnumerator.h",
+        "android/hardware/automotive/evs/1.0/IHwEvsEnumerator.h",
+        "android/hardware/automotive/evs/1.0/BnHwEvsEnumerator.h",
+        "android/hardware/automotive/evs/1.0/BpHwEvsEnumerator.h",
+        "android/hardware/automotive/evs/1.0/BsEvsEnumerator.h",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.automotive.evs@1.0",
+    generated_sources: ["android.hardware.automotive.evs@1.0_genc++"],
+    generated_headers: ["android.hardware.automotive.evs@1.0_genc++_headers"],
+    export_generated_headers: ["android.hardware.automotive.evs@1.0_genc++_headers"],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "android.hidl.base@1.0",
+    ],
+    export_shared_lib_headers: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "android.hidl.base@1.0",
+    ],
+}
diff --git a/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal
similarity index 98%
rename from evs/1.0/IEvsCamera.hal
rename to automotive/evs/1.0/IEvsCamera.hal
index d0559d7..1b55d1f 100644
--- a/evs/1.0/IEvsCamera.hal
+++ b/automotive/evs/1.0/IEvsCamera.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.evs@1.0;
+package android.hardware.automotive.evs@1.0;
 
 import types;
 import IEvsCameraStream;
diff --git a/evs/1.0/IEvsCameraStream.hal b/automotive/evs/1.0/IEvsCameraStream.hal
similarity index 96%
rename from evs/1.0/IEvsCameraStream.hal
rename to automotive/evs/1.0/IEvsCameraStream.hal
index fcd5717..4e743b2 100644
--- a/evs/1.0/IEvsCameraStream.hal
+++ b/automotive/evs/1.0/IEvsCameraStream.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.evs@1.0;
+package android.hardware.automotive.evs@1.0;
 
 
 /**
diff --git a/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal
similarity index 98%
rename from evs/1.0/IEvsDisplay.hal
rename to automotive/evs/1.0/IEvsDisplay.hal
index 8352221..bbad428 100644
--- a/evs/1.0/IEvsDisplay.hal
+++ b/automotive/evs/1.0/IEvsDisplay.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.evs@1.0;
+package android.hardware.automotive.evs@1.0;
 
 import types;
 
diff --git a/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal
similarity index 97%
rename from evs/1.0/IEvsEnumerator.hal
rename to automotive/evs/1.0/IEvsEnumerator.hal
index 3779866..334430b 100644
--- a/evs/1.0/IEvsEnumerator.hal
+++ b/automotive/evs/1.0/IEvsEnumerator.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.evs@1.0;
+package android.hardware.automotive.evs@1.0;
 
 import types;
 import IEvsCamera;
diff --git a/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp
similarity index 70%
rename from evs/1.0/default/Android.bp
rename to automotive/evs/1.0/default/Android.bp
index c47f035..51c3a94 100644
--- a/evs/1.0/default/Android.bp
+++ b/automotive/evs/1.0/default/Android.bp
@@ -1,5 +1,5 @@
 cc_binary {
-    name: "android.hardware.evs@1.0-service",
+    name: "android.hardware.automotive.evs@1.0-service",
     proprietary: true,
     relative_install_path: "hw",
     srcs: [
@@ -8,10 +8,10 @@
         "EvsEnumerator.cpp",
         "EvsDisplay.cpp"
     ],
-    init_rc: ["android.hardware.evs@1.0-service.rc"],
+    init_rc: ["android.hardware.automotive.evs@1.0-service.rc"],
 
     shared_libs: [
-        "android.hardware.evs@1.0",
+        "android.hardware.automotive.evs@1.0",
         "libui",
         "libbase",
         "libbinder",
diff --git a/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp
similarity index 98%
rename from evs/1.0/default/EvsCamera.cpp
rename to automotive/evs/1.0/default/EvsCamera.cpp
index df7e844..6bcf22a 100644
--- a/evs/1.0/default/EvsCamera.cpp
+++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "android.hardware.evs@1.0-service"
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
 
 #include "EvsCamera.h"
 
@@ -24,6 +24,7 @@
 
 namespace android {
 namespace hardware {
+namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
@@ -42,9 +43,9 @@
 // As it stands, if the client dies suddenly, the buffer may be stranded.
 
 EvsCamera::EvsCamera(const char *id) :
-    mFramesAllowed(0),
-    mFramesInUse(0),
-    mStreamState(STOPPED) {
+        mFramesAllowed(0),
+        mFramesInUse(0),
+        mStreamState(STOPPED) {
 
     ALOGD("EvsCamera instantiated");
 
@@ -96,7 +97,7 @@
 }
 
 
-// Methods from ::android::hardware::evs::V1_0::IEvsCamera follow.
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
 Return<void> EvsCamera::getId(getId_cb id_cb) {
     ALOGD("getId");
 
@@ -487,5 +488,6 @@
 } // namespace implementation
 } // namespace V1_0
 } // namespace evs
+} // namespace automotive
 } // namespace hardware
 } // namespace android
diff --git a/automotive/evs/1.0/default/EvsCamera.h b/automotive/evs/1.0/default/EvsCamera.h
new file mode 100644
index 0000000..ee91ca4
--- /dev/null
+++ b/automotive/evs/1.0/default/EvsCamera.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H
+
+#include <android/hardware/automotive/evs/1.0/types.h>
+#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <ui/GraphicBuffer.h>
+
+#include <thread>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_0 {
+namespace implementation {
+
+
+class EvsCamera : public IEvsCamera {
+public:
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+    Return<void> getId(getId_cb id_cb) override;
+
+    Return <EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+
+    Return <EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream>& stream) override;
+
+    Return<void> doneWithFrame(const BufferDesc& buffer) override;
+
+    Return<void> stopVideoStream() override;
+
+    Return <int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
+
+    Return <EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+    // Implementation details
+    EvsCamera(const char* id);
+
+    virtual ~EvsCamera() override;
+
+    const CameraDesc& getDesc() { return mDescription; };
+
+    static const char kCameraName_Backup[];
+    static const char kCameraName_RightTurn[];
+
+private:
+    // These three functions are expected to be called while mAccessLock is held
+    bool setAvailableFrames_Locked(unsigned bufferCount);
+
+    unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
+
+    unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
+
+    void generateFrames();
+
+    void fillTestFrame(const BufferDesc& buff);
+
+    CameraDesc mDescription = {};  // The properties of this camera
+
+    std::thread mCaptureThread;     // The thread we'll use to synthesize frames
+
+    uint32_t mWidth = 0;        // Horizontal pixel count in the buffers
+    uint32_t mHeight = 0;        // Vertical pixel count in the buffers
+    uint32_t mFormat = 0;        // Values from android_pixel_format_t [TODO: YUV?  Leave opaque?]
+    uint32_t mUsage = 0;        // Values from from Gralloc.h
+    uint32_t mStride = 0;        // Bytes per line in the buffers
+
+    sp <IEvsCameraStream> mStream = nullptr;  // The callback used to deliver each frame
+
+    struct BufferRecord {
+        buffer_handle_t handle;
+        bool inUse;
+
+        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
+    };
+
+    std::vector <BufferRecord> mBuffers;           // Graphics buffers to transfer images
+    unsigned mFramesAllowed;     // How many buffers are we currently using
+    unsigned mFramesInUse;       // How many buffers are currently outstanding
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+    };
+    StreamStateValues mStreamState;
+
+    // Syncrhonization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H
diff --git a/evs/1.0/default/EvsDisplay.cpp b/automotive/evs/1.0/default/EvsDisplay.cpp
similarity index 98%
rename from evs/1.0/default/EvsDisplay.cpp
rename to automotive/evs/1.0/default/EvsDisplay.cpp
index bbfff35..a1a76d0 100644
--- a/evs/1.0/default/EvsDisplay.cpp
+++ b/automotive/evs/1.0/default/EvsDisplay.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "android.hardware.evs@1.0-service"
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
 
 #include "EvsDisplay.h"
 
@@ -24,6 +24,7 @@
 
 namespace android {
 namespace hardware {
+namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
@@ -242,7 +243,7 @@
 
         // If we failed to lock the pixel buffer, we're about to crash, but log it first
         if (!pixels) {
-            ALOGE("Camera failed to gain access to image buffer for reading");
+            ALOGE("Display failed to gain access to image buffer for reading");
         }
 
         // Check the test pixels
@@ -302,5 +303,6 @@
 } // namespace implementation
 } // namespace V1_0
 } // namespace evs
+} // namespace automotive
 } // namespace hardware
 } // namespace android
diff --git a/evs/1.0/default/EvsDisplay.h b/automotive/evs/1.0/default/EvsDisplay.h
similarity index 81%
rename from evs/1.0/default/EvsDisplay.h
rename to automotive/evs/1.0/default/EvsDisplay.h
index f4d7ee9..fcf4a06 100644
--- a/evs/1.0/default/EvsDisplay.h
+++ b/automotive/evs/1.0/default/EvsDisplay.h
@@ -14,21 +14,22 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_EVS_V1_0_EVSDISPLAY_H
-#define ANDROID_HARDWARE_EVS_V1_0_EVSDISPLAY_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H
 
-#include <android/hardware/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
 #include <ui/GraphicBuffer.h>
 
 namespace android {
 namespace hardware {
+namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
 
 class EvsDisplay : public IEvsDisplay {
 public:
-    // Methods from ::android::hardware::evs::V1_0::IEvsDisplay follow.
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
     Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb)  override;
     Return<EvsResult> setDisplayState(DisplayState state)  override;
     Return<DisplayState> getDisplayState()  override;
@@ -52,7 +53,8 @@
 } // namespace implementation
 } // namespace V1_0
 } // namespace evs
+} // namespace automotive
 } // namespace hardware
 } // namespace android
 
-#endif  // ANDROID_HARDWARE_EVS_V1_0_EVSDISPLAY_H
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H
diff --git a/evs/1.0/default/EvsEnumerator.cpp b/automotive/evs/1.0/default/EvsEnumerator.cpp
similarity index 96%
rename from evs/1.0/default/EvsEnumerator.cpp
rename to automotive/evs/1.0/default/EvsEnumerator.cpp
index 4bf77f3..e54f699 100644
--- a/evs/1.0/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.0/default/EvsEnumerator.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "android.hardware.evs@1.0-service"
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
 
 #include "EvsEnumerator.h"
 #include "EvsCamera.h"
@@ -22,6 +22,7 @@
 
 namespace android {
 namespace hardware {
+namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
@@ -42,7 +43,7 @@
     mCameraList.emplace_back( new EvsCamera(EvsCamera::kCameraName_RightTurn), false );
 }
 
-// Methods from ::android::hardware::evs::V1_0::IEvsEnumerator follow.
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
 Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb)  {
     ALOGD("getCameraList");
 
@@ -168,5 +169,6 @@
 } // namespace implementation
 } // namespace V1_0
 } // namespace evs
+} // namespace automotive
 } // namespace hardware
 } // namespace android
diff --git a/evs/1.0/default/EvsEnumerator.h b/automotive/evs/1.0/default/EvsEnumerator.h
similarity index 78%
rename from evs/1.0/default/EvsEnumerator.h
rename to automotive/evs/1.0/default/EvsEnumerator.h
index 0e719bd..3d6e264 100644
--- a/evs/1.0/default/EvsEnumerator.h
+++ b/automotive/evs/1.0/default/EvsEnumerator.h
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_EVS_V1_0_EVSCAMERAENUMERATOR_H
-#define ANDROID_HARDWARE_EVS_V1_0_EVSCAMERAENUMERATOR_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
 
-#include <android/hardware/evs/1.0/IEvsEnumerator.h>
-#include <android/hardware/evs/1.0/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
 
 #include <list>
 
@@ -26,13 +26,14 @@
 
 namespace android {
 namespace hardware {
+namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
 
 class EvsEnumerator : public IEvsEnumerator {
 public:
-    // Methods from ::android::hardware::evs::V1_0::IEvsEnumerator follow.
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
     Return<void> getCameraList(getCameraList_cb _hidl_cb)  override;
     Return<sp<IEvsCamera>> openCamera(const hidl_string& cameraId) override;
     Return<void> closeCamera(const ::android::sp<IEvsCamera>& carCamera)  override;
@@ -57,7 +58,8 @@
 } // namespace implementation
 } // namespace V1_0
 } // namespace evs
+} // namespace automotive
 } // namespace hardware
 } // namespace android
 
-#endif  // ANDROID_HARDWARE_EVS_V1_0_EVSCAMERAENUMERATOR_H
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
diff --git a/evs/1.0/default/ServiceNames.h b/automotive/evs/1.0/default/ServiceNames.h
similarity index 100%
rename from evs/1.0/default/ServiceNames.h
rename to automotive/evs/1.0/default/ServiceNames.h
diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
new file mode 100644
index 0000000..8957ecf
--- /dev/null
+++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
@@ -0,0 +1,4 @@
+service evs-hal-1-0 /vendor/bin/hw/android.hardware.automotive.evs@1.0-service
+    class hal
+    user cameraserver
+    group camera
diff --git a/evs/1.0/default/service.cpp b/automotive/evs/1.0/default/service.cpp
similarity index 87%
rename from evs/1.0/default/service.cpp
rename to automotive/evs/1.0/default/service.cpp
index 112c879..1b64e44 100644
--- a/evs/1.0/default/service.cpp
+++ b/automotive/evs/1.0/default/service.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "android.hardware.evs@1.0-service"
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
 
 #include <unistd.h>
 
@@ -33,11 +33,11 @@
 using android::hardware::joinRpcThreadpool;
 
 // Generated HIDL files
-using android::hardware::evs::V1_0::IEvsEnumerator;
-using android::hardware::evs::V1_0::IEvsDisplay;
+using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_0::IEvsDisplay;
 
 // The namespace in which all our implementation code lives
-using namespace android::hardware::evs::V1_0::implementation;
+using namespace android::hardware::automotive::evs::V1_0::implementation;
 using namespace android;
 
 
diff --git a/evs/1.0/types.hal b/automotive/evs/1.0/types.hal
similarity index 98%
rename from evs/1.0/types.hal
rename to automotive/evs/1.0/types.hal
index 6b580cf..661c2a9 100644
--- a/evs/1.0/types.hal
+++ b/automotive/evs/1.0/types.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.evs@1.0;
+package android.hardware.automotive.evs@1.0;
 
 
 /*
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
index ba4a6cd..9b3323d 100644
--- a/automotive/vehicle/2.0/default/Android.mk
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -118,6 +118,7 @@
 
 LOCAL_SRC_FILES:= \
     tests/AccessControlConfigParser_test.cpp \
+    tests/RecurrentTimer_test.cpp \
     tests/SubscriptionManager_test.cpp \
     tests/VehicleHalManager_test.cpp \
     tests/VehicleObjectPool_test.cpp \
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
new file mode 100644
index 0000000..be25adc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
+#define android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <functional>
+#include <list>
+#include <mutex>
+#include <set>
+#include <thread>
+#include <unordered_map>
+
+/**
+ * This class allows to specify multiple time intervals to receive
+ * notifications. A single thread is used internally.
+ */
+class RecurrentTimer {
+private:
+    using Nanos = std::chrono::nanoseconds;
+    using Clock = std::chrono::steady_clock;
+    using TimePoint = std::chrono::time_point<Clock, Nanos>;
+public:
+    using Action = std::function<void(const std::vector<int32_t>& cookies)>;
+
+    RecurrentTimer(const Action& action) : mAction(action) {
+        mTimerThread = std::thread(&RecurrentTimer::loop, this, action);
+    }
+
+    virtual ~RecurrentTimer() {
+        stop();
+    }
+
+    /**
+     * Registers recurrent event for a given interval. Registred events are distinguished by
+     * cookies thus calling this method multiple times with the same cookie will override the
+     * interval provided before.
+     */
+    void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) {
+        TimePoint now = Clock::now();
+        // Align event time point among all intervals. Thus if we have two intervals 1ms and 2ms,
+        // during every second wake-up both intervals will be triggered.
+        TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());
+
+        {
+            std::lock_guard<std::mutex> g(mLock);
+            mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime };
+        }
+        mCond.notify_one();
+    }
+
+    void unregisterRecurrentEvent(int32_t cookie) {
+        {
+            std::lock_guard<std::mutex> g(mLock);
+            mCookieToEventsMap.erase(cookie);
+        }
+        mCond.notify_one();
+    }
+
+
+private:
+
+    struct RecurrentEvent {
+        Nanos interval;
+        int32_t cookie;
+        TimePoint absoluteTime;  // Absolute time of the next event.
+
+        void updateNextEventTime(TimePoint now) {
+            // We want to move time to next event by adding some number of intervals (usually 1)
+            // to previous absoluteTime.
+            int intervalMultiplier = (now - absoluteTime) / interval;
+            if (intervalMultiplier <= 0) intervalMultiplier = 1;
+            absoluteTime += intervalMultiplier * interval;
+        }
+    };
+
+    void loop(const Action& action) {
+        static constexpr auto kInvalidTime = TimePoint(Nanos::max());
+
+        std::vector<int32_t> cookies;
+
+        while (!mStopRequested) {
+            auto now = Clock::now();
+            auto nextEventTime = kInvalidTime;
+            cookies.clear();
+
+            {
+                std::unique_lock<std::mutex> g(mLock);
+
+                for (auto&& it : mCookieToEventsMap) {
+                    RecurrentEvent& event = it.second;
+                    if (event.absoluteTime <= now) {
+                        event.updateNextEventTime(now);
+                        cookies.push_back(event.cookie);
+                    }
+
+                    if (nextEventTime > event.absoluteTime) {
+                        nextEventTime = event.absoluteTime;
+                    }
+                }
+            }
+
+            if (cookies.size() != 0) {
+                action(cookies);
+            }
+
+            std::unique_lock<std::mutex> g(mLock);
+            mCond.wait_until(g, nextEventTime);  // nextEventTime can be nanoseconds::max()
+        }
+    }
+
+    void stop() {
+        mStopRequested = true;
+        {
+            std::lock_guard<std::mutex> g(mLock);
+            mCookieToEventsMap.clear();
+        }
+        mCond.notify_one();
+        if (mTimerThread.joinable()) {
+            mTimerThread.join();
+        }
+    }
+private:
+    mutable std::mutex mLock;
+    std::thread mTimerThread;
+    std::condition_variable mCond;
+    std::atomic_bool mStopRequested { false };
+    Action mAction;
+    std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap;
+};
+
+
+#endif  // android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
index 6a12b77..a808c66 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
@@ -23,6 +23,7 @@
 #include <list>
 
 #include <android/log.h>
+#include <hidl/HidlSupport.h>
 #include <hwbinder/IPCThreadState.h>
 
 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
@@ -50,10 +51,8 @@
     }
 
     void addOrUpdateSubscription(const SubscribeOptions &opts);
-
-    bool isSubscribed(int32_t propId,
-                      int32_t areaId,
-                      SubscribeFlags flags);
+    bool isSubscribed(int32_t propId, int32_t areaId, SubscribeFlags flags);
+    std::vector<int32_t> getSubscribedProperties() const;
 
 private:
     const sp<IVehicleCallback> mCallback;
@@ -85,15 +84,29 @@
 
 class SubscriptionManager {
 public:
-    virtual ~SubscriptionManager() {}
+    using OnPropertyUnsubscribed = std::function<void(int32_t)>;
+
+    /**
+     * Constructs SubscriptionManager
+     *
+     * @param onPropertyUnsubscribed - this callback function will be called when there are no
+     *                                    more client subscribed to particular property.
+     */
+    SubscriptionManager(const OnPropertyUnsubscribed& onPropertyUnsubscribed)
+            : mOnPropertyUnsubscribed(onPropertyUnsubscribed),
+                mCallbackDeathRecipient(new DeathRecipient(
+                    std::bind(&SubscriptionManager::onCallbackDead, this, std::placeholders::_1)))
+    {}
+
+    ~SubscriptionManager() = default;
 
     /**
      * Updates subscription. Returns the vector of properties subscription that
      * needs to be updated in VehicleHAL.
      */
-    std::list<SubscribeOptions> addOrUpdateSubscription(
-            const sp<IVehicleCallback>& callback,
-            const hidl_vec<SubscribeOptions>& optionList);
+    StatusCode addOrUpdateSubscription(const sp<IVehicleCallback>& callback,
+                                       const hidl_vec<SubscribeOptions>& optionList,
+                                       std::list<SubscribeOptions>* outUpdatedOptions);
 
     /**
      * Returns a list of IVehicleCallback -> list of VehiclePropValue ready for
@@ -103,30 +116,48 @@
             const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
             SubscribeFlags flags) const;
 
-    std::list<sp<HalClient>> getSubscribedClients(
-        int32_t propId, int32_t area, SubscribeFlags flags) const;
-
+    std::list<sp<HalClient>> getSubscribedClients(int32_t propId,
+                                                  int32_t area,
+                                                  SubscribeFlags flags) const;
     /**
-     * Returns true the client was unsubscribed successfully and there are
-     * no more clients subscribed to given propId.
+     * If there are no clients subscribed to given properties than callback function provided
+     * in the constructor will be called.
      */
-    bool unsubscribe(const sp<IVehicleCallback>& callback,
-                     int32_t propId);
+    void unsubscribe(const sp<IVehicleCallback>& callback, int32_t propId);
 private:
-    std::list<sp< HalClient>> getSubscribedClientsLocked(
-            int32_t propId, int32_t area, SubscribeFlags flags) const;
+    std::list<sp<HalClient>> getSubscribedClientsLocked(int32_t propId,
+                                                        int32_t area,
+                                                        SubscribeFlags flags) const;
 
-    bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts,
-                                          SubscribeOptions *out);
+    bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts, SubscribeOptions* out);
 
-    void addClientToPropMapLocked(int32_t propId,
-                                  const sp<HalClient> &client);
+    void addClientToPropMapLocked(int32_t propId, const sp<HalClient>& client);
 
-    sp<HalClientVector> getClientsForPropertyLocked(
-            int32_t propId) const;
+    sp<HalClientVector> getClientsForPropertyLocked(int32_t propId) const;
 
-    sp<HalClient> getOrCreateHalClientLocked(
-            const sp<IVehicleCallback> &callback);
+    sp<HalClient> getOrCreateHalClientLocked(const sp<IVehicleCallback> &callback);
+
+    void onCallbackDead(uint64_t cookie);
+
+private:
+    using OnClientDead = std::function<void(uint64_t)>;
+
+    class DeathRecipient : public hidl_death_recipient {
+    public:
+        DeathRecipient(const OnClientDead& onClientDead)
+            : mOnClientDead(onClientDead) {}
+        ~DeathRecipient() = default;
+
+        DeathRecipient(const DeathRecipient& ) = delete;
+        DeathRecipient& operator=(const DeathRecipient&) = delete;
+
+        void serviceDied(uint64_t cookie,
+                         const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+            mOnClientDead(cookie);
+        }
+    private:
+        OnClientDead mOnClientDead;
+    };
 
 private:
     using MuxGuard = std::lock_guard<std::mutex>;
@@ -136,6 +167,9 @@
     std::map<sp<IVehicleCallback>, sp<HalClient>> mClients;
     std::map<int32_t, sp<HalClientVector>> mPropToClients;
     std::map<int32_t, SubscribeOptions> mHalEventSubscribeOptions;
+
+    OnPropertyUnsubscribed mOnPropertyUnsubscribed;
+    sp<DeathRecipient> mCallbackDeathRecipient;
 };
 
 
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
index 4bff4d1..b8ab309 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -56,7 +56,9 @@
 class VehicleHalManager : public IVehicle {
 public:
     VehicleHalManager(VehicleHal* vehicleHal)
-        : mHal(vehicleHal) {
+        : mHal(vehicleHal),
+          mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed,
+                                         this, std::placeholders::_1)) {
         init();
     }
 
@@ -105,6 +107,8 @@
                   int32_t propertyId,
                   VehiclePropertyAccess requiredAccess) const;
 
+    void onAllClientsUnsubscribed(int32_t propertyId);
+
     static bool isSubscribable(const VehiclePropConfig& config,
                                SubscribeFlags flags);
     static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
diff --git a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
index f6f2758..4493a41 100644
--- a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
@@ -19,6 +19,7 @@
 #include "SubscriptionManager.h"
 
 #include <cmath>
+#include <inttypes.h>
 
 #include <android/log.h>
 
@@ -58,6 +59,8 @@
 }
 
 void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts)  {
+    ALOGI("%s opts.propId: 0x%x", __func__, opts.propId);
+
     auto it = mSubscriptions.find(opts.propId);
     if (it == mSubscriptions.end()) {
         mSubscriptions.emplace(opts.propId, opts);
@@ -84,17 +87,33 @@
     return res;
 }
 
-std::list<SubscribeOptions> SubscriptionManager::addOrUpdateSubscription(
+std::vector<int32_t> HalClient::getSubscribedProperties() const {
+    std::vector<int32_t> props;
+    for (const auto& subscription : mSubscriptions) {
+        ALOGI("%s propId: 0x%x, propId: 0x%x", __func__, subscription.first, subscription.second.propId);
+        props.push_back(subscription.first);
+    }
+    return props;
+}
+
+StatusCode SubscriptionManager::addOrUpdateSubscription(
         const sp<IVehicleCallback> &callback,
-        const hidl_vec<SubscribeOptions> &optionList) {
-    std::list<SubscribeOptions> updatedSubscriptions;
+        const hidl_vec<SubscribeOptions> &optionList,
+        std::list<SubscribeOptions>* outUpdatedSubscriptions) {
+    outUpdatedSubscriptions->clear();
 
     MuxGuard g(mLock);
 
+    ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get());
+
     const sp<HalClient>& client = getOrCreateHalClientLocked(callback);
+    if (client.get() == nullptr) {
+        return StatusCode::INTERNAL_ERROR;
+    }
 
     for (size_t i = 0; i < optionList.size(); i++) {
         const SubscribeOptions& opts = optionList[i];
+        ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId);
         client->addOrUpdateSubscription(opts);
 
         addClientToPropMapLocked(opts.propId, client);
@@ -102,12 +121,12 @@
         if (SubscribeFlags::HAL_EVENT & opts.flags) {
             SubscribeOptions updated;
             if (updateHalEventSubscriptionLocked(opts, &updated)) {
-                updatedSubscriptions.push_back(updated);
+                outUpdatedSubscriptions->push_back(updated);
             }
         }
     }
 
-    return updatedSubscriptions;
+    return StatusCode::OK;
 }
 
 std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
@@ -205,6 +224,14 @@
         const sp<IVehicleCallback>& callback) {
     auto it = mClients.find(callback);
     if (it == mClients.end()) {
+        uint64_t cookie = reinterpret_cast<uint64_t>(callback.get());
+        ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie);
+        auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie);
+        if (!res.isOk()) {  // Client is already dead?
+            ALOGW("%s failed to link to death, client %p, err: %s",
+                  __func__, callback.get(), res.description().c_str());
+            return nullptr;
+        }
         IPCThreadState* self = IPCThreadState::self();
         pid_t pid = self->getCallingPid();
         uid_t uid = self->getCallingUid();
@@ -216,7 +243,7 @@
     }
 }
 
-bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
+void SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
                                       int32_t propId) {
     MuxGuard g(mLock);
     auto propertyClients = getClientsForPropertyLocked(propId);
@@ -243,13 +270,39 @@
         }
 
         if (!isClientSubscribedToOtherProps) {
+            auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient);
+            if (!res.isOk()) {
+                ALOGW("%s failed to unlink to death, client: %p, err: %s",
+                      __func__, client->getCallback().get(), res.description().c_str());
+            }
             mClients.erase(clientIter);
         }
     }
 
-    return (propertyClients == nullptr || propertyClients->isEmpty())
-            ? mHalEventSubscribeOptions.erase(propId) == 1
-            : false;
+    if (propertyClients == nullptr || propertyClients->isEmpty()) {
+        mHalEventSubscribeOptions.erase(propId);
+        mOnPropertyUnsubscribed(propId);
+    }
+}
+
+void SubscriptionManager::onCallbackDead(uint64_t cookie) {
+    ALOGI("%s, cookie: 0x%" PRIx64, __func__, cookie);
+    IVehicleCallback* callback = reinterpret_cast<IVehicleCallback*>(cookie);
+
+    std::vector<int32_t> props;
+    {
+        MuxGuard g(mLock);
+        const auto& it = mClients.find(callback);
+        if (it == mClients.end()) {
+            return;  // Nothing to do here, client wasn't subscribed to any properties.
+        }
+        const auto& halClient = it->second;
+        props = halClient->getSubscribedProperties();
+    }
+
+    for (int32_t propId : props) {
+        unsubscribe(callback, propId);
+    }
 }
 
 
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index 3a5e504..8906f6e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -43,8 +43,7 @@
  */
 constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
 
-Return<void> VehicleHalManager::getAllPropConfigs(
-        getAllPropConfigs_cb _hidl_cb) {
+Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
     ALOGI("getAllPropConfigs called");
     hidl_vec<VehiclePropConfig> hidlConfigs;
     auto& halConfig = mConfigIndex->getAllConfigs();
@@ -58,9 +57,8 @@
     return Void();
 }
 
-Return<void> VehicleHalManager::getPropConfigs(
-        const hidl_vec<int32_t> &properties,
-        getPropConfigs_cb _hidl_cb) {
+Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties,
+                                               getPropConfigs_cb _hidl_cb) {
     std::vector<VehiclePropConfig> configs;
     for (size_t i = 0; i < properties.size(); i++) {
         auto prop = properties[i];
@@ -77,8 +75,7 @@
     return Void();
 }
 
-Return<void> VehicleHalManager::get(
-        const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
+Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
     const auto* config = getPropConfigOrNull(requestedPropValue.prop);
     if (config == nullptr) {
         ALOGE("Failed to get value: config not found, property: 0x%x",
@@ -119,9 +116,8 @@
     return Return<StatusCode>(status);
 }
 
-Return<StatusCode> VehicleHalManager::subscribe(
-        const sp<IVehicleCallback> &callback,
-        const hidl_vec<SubscribeOptions> &options) {
+Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
+                                                const hidl_vec<SubscribeOptions> &options) {
     hidl_vec<SubscribeOptions> verifiedOptions(options);
     auto caller = getCaller();
     for (size_t i = 0; i < verifiedOptions.size(); i++) {
@@ -135,6 +131,11 @@
             return StatusCode::INVALID_ARG;
         }
 
+        if (ops.flags == SubscribeFlags::UNDEFINED) {
+            ALOGE("Failed to subscribe: undefined flag in options provided");
+            return StatusCode::INVALID_ARG;
+        }
+
         if (!checkAcl(caller.uid, config->prop, VehiclePropertyAccess::READ)) {
             return StatusCode::ACCESS_DENIED;
         }
@@ -157,22 +158,24 @@
         ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
     }
 
-    std::list<SubscribeOptions> updatedOptions =
-        mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions);
+    std::list<SubscribeOptions> updatedOptions;
+    auto res = mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions,
+                                                            &updatedOptions);
+    if (StatusCode::OK != res) {
+        ALOGW("%s failed to subscribe, error code: %d", __func__, res);
+        return res;
+    }
 
     for (auto opt : updatedOptions) {
         mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
     }
-    // TODO(pavelm): link to death callback (not implemented yet in HIDL)
 
     return StatusCode::OK;
 }
 
-Return<StatusCode> VehicleHalManager::unsubscribe(
-        const sp<IVehicleCallback>& callback, int32_t propId) {
-    if (mSubscriptionManager.unsubscribe(callback, propId)) {
-        mHal->unsubscribe(propId);
-    }
+Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
+                                                  int32_t propId) {
+    mSubscriptionManager.unsubscribe(callback, propId);
     return StatusCode::OK;
 }
 
@@ -239,8 +242,7 @@
     }
 }
 
-void VehicleHalManager::onBatchHalEvent(
-        const std::vector<VehiclePropValuePtr>& values) {
+void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
     const auto& clientValues = mSubscriptionManager.distributeValuesToClients(
             values, SubscribeFlags::HAL_EVENT);
 
@@ -257,7 +259,12 @@
         for (VehiclePropValue* pValue : cv.values) {
             shallowCopy(&(vec)[i++], *pValue);
         }
-        cv.client->getCallback()->onPropertyEvent(vec);
+        auto status = cv.client->getCallback()->onPropertyEvent(vec);
+        if (!status.isOk()) {
+            ALOGE("Failed to notify client %s, err: %s",
+                  toString(cv.client->getCallback()).c_str(),
+                  status.description().c_str());
+        }
     }
 }
 
@@ -379,6 +386,10 @@
     }
 }
 
+void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
+    mHal->unsubscribe(propertyId);
+}
+
 }  // namespace V2_0
 }  // namespace vehicle
 }  // namespace automotive
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 9591689..596ad85 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
@@ -147,6 +147,15 @@
     },
 
     {
+        .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
+        .access = VehiclePropertyAccess::READ,
+        // TODO(bryaneyler): Support ON_CHANGE as well.
+        .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+        .minSampleRate = 1.0f,
+        .maxSampleRate = 2.0f,
+    },
+
+    {
         .prop = toInt(VehicleProperty::NIGHT_MODE),
         .access = VehiclePropertyAccess::READ,
         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -192,6 +201,14 @@
         .prop = toInt(VehicleProperty::IGNITION_STATE),
         .access = VehiclePropertyAccess::READ,
         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+    },
+
+    {
+        .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+        .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
+        .maxSampleRate = 10,  // 10 Hz, every 100 ms
     }
 };
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
index 7a66c04..2214100 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -118,6 +118,7 @@
 
     val.prop = protoVal.prop();
     val.areaId = protoVal.area_id();
+    val.timestamp = elapsedRealtimeNano();
 
     // Copy value data if it is set.  This automatically handles complex data types if needed.
     if (protoVal.has_string_value()) {
@@ -176,7 +177,7 @@
     if (prop != mProps.end()) {
         return prop->second.get();
     }
-    ALOGW("%s: Property not found:  propId = 0x%x, areaId = 0x%x", __FUNCTION__, propId, areaId);
+    ALOGW("%s: Property not found:  propId = 0x%x, areaId = 0x%x", __func__, propId, areaId);
     return nullptr;
 }
 
@@ -202,7 +203,7 @@
             doSetProperty(rxMsg, respMsg);
             break;
         default:
-            ALOGW("%s: Unknown message received, type = %d", __FUNCTION__, rxMsg.msg_type());
+            ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
             respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
             break;
         }
@@ -210,7 +211,7 @@
         // Send the reply
         txMsg(respMsg);
     } else {
-        ALOGE("%s: ParseFromString() failed. msgSize=%d", __FUNCTION__, static_cast<int>(msg.size()));
+        ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
     }
 }
 
@@ -266,7 +267,7 @@
         }
         break;
     default:
-        ALOGW("%s: Unknown property type:  0x%x", __FUNCTION__, toInt(getPropType(cfg.prop)));
+        ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
         break;
     }
 
@@ -317,7 +318,7 @@
             parseRxProtoBuf(msg);
         } else {
             // This happens when connection is closed
-            ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes,
+            ALOGD("%s: numBytes=%d, msgSize=%d", __func__, numBytes,
                   static_cast<int32_t>(msg.size()));
             break;
         }
@@ -396,6 +397,9 @@
     case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
         prop->value.floatValues[0] = 16;
         break;
+    case toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE):
+        prop->value.floatValues[0] = 25;
+        break;
     case toInt(VehicleProperty::NIGHT_MODE):
         prop->value.int32Values[0] = 0;
         break;
@@ -408,6 +412,9 @@
     case toInt(VehicleProperty::INFO_FUEL_CAPACITY):
         prop->value.floatValues[0] = 0.75f;
         break;
+    case toInt(VehicleProperty::ENGINE_OIL_TEMP):
+        prop->value.floatValues[0] = 101;
+        break;
     case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
         prop->value.int32Values[0] = 7;
         break;
@@ -415,7 +422,7 @@
         prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON);
         break;
     default:
-        ALOGW("%s: propId=0x%x not found", __FUNCTION__, prop->prop);
+        ALOGW("%s: propId=0x%x not found", __func__, prop->prop);
         break;
     }
 }
@@ -434,10 +441,10 @@
         }
 
         if (retVal < 0) {
-            ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __FUNCTION__, retVal, errno);
+            ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
         }
     } else {
-        ALOGE("%s: SerializeToString failed!", __FUNCTION__);
+        ALOGE("%s: SerializeToString failed!", __func__);
     }
 }
 
@@ -453,7 +460,7 @@
         VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId);
         if (internalPropValue != nullptr) {
             internalPropValue->value = propValue.value;
-            internalPropValue->timestamp = elapsedRealtimeNano();
+            internalPropValue->timestamp = propValue.timestamp;
             status = StatusCode::OK;
         }
     }
@@ -566,10 +573,8 @@
                 break;
             }
             continue;
-            break;
-        case VehiclePropertyType::MASK:
         default:
-            ALOGW("%s: propType=0x%x not found", __FUNCTION__, propType);
+            ALOGE("%s: propType=0x%x not found", __func__, propType);
             vecSize = 0;
             break;
         }
@@ -602,6 +607,69 @@
     mThread = std::thread(&DefaultVehicleHal::rxThread, this);
 }
 
+void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
+    VehiclePropValuePtr v;
+
+    auto& pool = *getValuePool();
+
+    for (int32_t property : properties) {
+        if (isContinuousProperty(property)) {
+            // In real implementation this value should be read from sensor, random
+            // value used for testing purpose only.
+            std::lock_guard<std::mutex> lock(mPropsMutex);
+
+            VehiclePropValue *internalPropValue = getVehiclePropValueLocked(property);
+            if (internalPropValue != nullptr) {
+                v = pool.obtain(*internalPropValue);
+            }
+            if (VehiclePropertyType::FLOAT == getPropType(property)) {
+                // Just get some randomness to continuous properties to see slightly differnt values
+                // on the other end.
+                v->value.floatValues[0] = v->value.floatValues[0] + std::rand() % 5;
+            }
+        } else {
+            ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
+        }
+
+        if (v.get()) {
+            v->timestamp = elapsedRealtimeNano();
+            doHalEvent(std::move(v));
+        }
+    }
+}
+
+StatusCode DefaultVehicleHal::subscribe(int32_t property, int32_t,
+                                        float sampleRate) {
+    ALOGI("subscribe called for property: 0x%x, sampleRate: %f", property, sampleRate);
+
+    if (isContinuousProperty(property)) {
+        mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
+    }
+    return StatusCode::OK;
+}
+
+StatusCode DefaultVehicleHal::unsubscribe(int32_t property) {
+    ALOGI("%s propId: 0x%x", __func__, property);
+    if (isContinuousProperty(property)) {
+        mRecurrentTimer.unregisterRecurrentEvent(property);
+    }
+    return StatusCode::OK;
+}
+
+const VehiclePropConfig* DefaultVehicleHal::getPropConfig(int32_t propId) const {
+    auto it = mPropConfigMap.find(propId);
+    return it == mPropConfigMap.end() ? nullptr : it->second;
+}
+
+bool DefaultVehicleHal::isContinuousProperty(int32_t propId) const {
+    const VehiclePropConfig* config = getPropConfig(propId);
+    if (config == nullptr) {
+        ALOGW("Config not found for property: 0x%x", propId);
+        return false;
+    }
+    return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
+}
+
 }  // impl
 
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
index 1ad8702..98eef27 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
@@ -28,6 +28,7 @@
 #include "CommBase.h"
 #include "VehicleHalProto.pb.h"
 
+#include <vhal_v2_0/RecurrentTimer.h>
 #include <vhal_v2_0/VehicleHal.h>
 
 #include "DefaultConfig.h"
@@ -43,7 +44,13 @@
 
 class DefaultVehicleHal : public VehicleHal {
 public:
-    DefaultVehicleHal() : mThread() {}
+    DefaultVehicleHal() : mRecurrentTimer(
+            std::bind(&DefaultVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) {
+        for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
+            mPropConfigMap[kVehicleProperties->prop] = &kVehicleProperties[i];
+        }
+    }
+
     ~DefaultVehicleHal() override {
         // Notify thread to finish and wait for it to terminate
         mExit = 1;
@@ -66,16 +73,9 @@
 
     StatusCode set(const VehiclePropValue& propValue) override;
 
-    StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) {
-        ALOGD("%s: not implemented: prop=0x%x, areas=0x%x, rate=%f", __FUNCTION__, property,
-              areas, sampleRate);
-        return StatusCode::OK;
-    }
+    StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
 
-    StatusCode unsubscribe(int32_t property) {
-        ALOGD("%s: not implemented: prop=0x%x", __FUNCTION__, property);
-        return StatusCode::OK;
-    }
+    StatusCode unsubscribe(int32_t property) override;
 
 private:
     void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
@@ -83,7 +83,9 @@
     void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
     void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
     void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
-    VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId);
+    VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId = 0);
+    const VehiclePropConfig* getPropConfig(int32_t propId) const;
+    bool isContinuousProperty(int32_t propId) const;
     void parseRxProtoBuf(std::vector<uint8_t>& msg);
     void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
                                     const VehiclePropConfig& cfg);
@@ -94,6 +96,13 @@
     void rxThread();
     void txMsg(emulator::EmulatorMessage& txMsg);
     StatusCode updateProperty(const VehiclePropValue& propValue);
+
+    constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
+        return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
+    }
+
+    void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
+
 private:
     std::map<
         std::pair<int32_t /*VehicleProperty*/, int32_t /*areaId*/>,
@@ -103,6 +112,8 @@
     std::mutex mPropsMutex;
     std::thread mThread;
     std::unique_ptr<CommBase> mComm{nullptr};
+    RecurrentTimer mRecurrentTimer;
+    std::unordered_map<int32_t, const VehiclePropConfig*> mPropConfigMap;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
new file mode 100644
index 0000000..9fc17c6
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include "vhal_v2_0/RecurrentTimer.h"
+
+namespace {
+
+using std::chrono::nanoseconds;
+using std::chrono::milliseconds;
+
+#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \
+ASSERT_LE(val1 - tolerance, val2); \
+ASSERT_GE(val1 + tolerance, val2); \
+
+
+TEST(RecurrentTimerTest, oneInterval) {
+    std::atomic<int64_t> counter { 0L };
+    auto counterRef = std::ref(counter);
+    RecurrentTimer timer([&counterRef](const std::vector<int32_t>& cookies) {
+        ASSERT_EQ(1u, cookies.size());
+        ASSERT_EQ(0xdead, cookies.front());
+        counterRef.get()++;
+    });
+
+    timer.registerRecurrentEvent(milliseconds(1), 0xdead);
+    std::this_thread::sleep_for(milliseconds(100));
+    ASSERT_EQ_WITH_TOLERANCE(100, counter.load(), 20);
+}
+
+TEST(RecurrentTimerTest, multipleIntervals) {
+    std::atomic<int64_t> counter1ms { 0L };
+    std::atomic<int64_t> counter5ms { 0L };
+    auto counter1msRef = std::ref(counter1ms);
+    auto counter5msRef = std::ref(counter5ms);
+    RecurrentTimer timer(
+            [&counter1msRef, &counter5msRef](const std::vector<int32_t>& cookies) {
+        for (int32_t cookie : cookies) {
+            if (cookie == 0xdead) {
+                counter1msRef.get()++;
+            } else if (cookie == 0xbeef) {
+                counter5msRef.get()++;
+            } else {
+                FAIL();
+            }
+        }
+    });
+
+    timer.registerRecurrentEvent(milliseconds(1), 0xdead);
+    timer.registerRecurrentEvent(milliseconds(5), 0xbeef);
+
+    std::this_thread::sleep_for(milliseconds(100));
+    ASSERT_EQ_WITH_TOLERANCE(100, counter1ms.load(), 20);
+    ASSERT_EQ_WITH_TOLERANCE(20, counter5ms.load(), 5);
+}
+
+}  // anonymous namespace
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
index e13d003..7ec9b79 100644
--- a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include <unordered_map>
+#include <functional>
 #include <iostream>
+#include <unordered_map>
 
 #include <gtest/gtest.h>
 
@@ -35,8 +36,9 @@
 
 class SubscriptionManagerTest : public ::testing::Test {
 public:
-    SubscriptionManager manager;
+    SubscriptionManagerTest() : manager(([this](int x) { onPropertyUnsubscribed(x); })) {}
 
+    SubscriptionManager manager;
     static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED);
     static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
 
@@ -44,6 +46,10 @@
     sp<IVehicleCallback> cb2 = new MockedVehicleCallback();
     sp<IVehicleCallback> cb3 = new MockedVehicleCallback();
 
+    void SetUp() override {
+        lastUnsubscribedProperty = -1;
+    }
+
     hidl_vec<SubscribeOptions> subscrToProp1 = {
         SubscribeOptions {
             .propId = PROP1,
@@ -90,12 +96,31 @@
         return manager.getSubscribedClients(PROP2, 0,
                                             SubscribeFlags::DEFAULT);
     }
+
+    void onPropertyUnsubscribed(int propertyId) {
+        // Called when there are no clients who subscribed to particular property. This can happen
+        // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected.
+        lastUnsubscribedProperty = propertyId;
+    }
+
+    void assertOnPropertyUnsubscribedNotCalled() {
+        ASSERT_EQ(-1, lastUnsubscribedProperty);
+    }
+
+    void assertLastUnsubscribedProperty(int expectedPropertyId) {
+        ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty);
+        lastUnsubscribedProperty = -1;
+    }
+
+private:
+    int lastUnsubscribedProperty;
 };
 
 
 TEST_F(SubscriptionManagerTest, multipleClients) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
-    manager.addOrUpdateSubscription(cb2, subscrToProp1);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp1, &updatedOptions));
 
     auto clients = manager.getSubscribedClients(
             PROP1,
@@ -106,7 +131,8 @@
 }
 
 TEST_F(SubscriptionManagerTest, negativeCases) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
 
     // Wrong zone
     auto clients = manager.getSubscribedClients(
@@ -131,7 +157,8 @@
 }
 
 TEST_F(SubscriptionManagerTest, mulipleSubscriptions) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
 
     auto clients = manager.getSubscribedClients(
             PROP1,
@@ -142,13 +169,13 @@
 
     // Same property, but different zone, to make sure we didn't unsubscribe
     // from previous zone.
-    manager.addOrUpdateSubscription(cb1, {
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, {
         SubscribeOptions {
                 .propId = PROP1,
                 .vehicleAreas = toInt(VehicleAreaZone::ROW_2),
                 .flags = SubscribeFlags::DEFAULT
             }
-        });
+        }, &updatedOptions));
 
     clients = manager.getSubscribedClients(PROP1,
                                            toInt(VehicleAreaZone::ROW_1_LEFT),
@@ -162,31 +189,38 @@
 }
 
 TEST_F(SubscriptionManagerTest, unsubscribe) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
-    manager.addOrUpdateSubscription(cb2, subscrToProp2);
-    manager.addOrUpdateSubscription(cb3, subscrToProp1and2);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp2, &updatedOptions));
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb3, subscrToProp1and2,
+                                                              &updatedOptions));
 
     ASSERT_ALL_EXISTS({cb1, cb3}, extractCallbacks(clientsToProp1()));
     ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
 
-    ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+    manager.unsubscribe(cb1, PROP1);
+    assertOnPropertyUnsubscribedNotCalled();
     ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1()));
 
     // Make sure nothing changed in PROP2 so far.
     ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
 
     // No one subscribed to PROP1, subscription for PROP2 is not affected.
-    ASSERT_TRUE(manager.unsubscribe(cb3, PROP1));
+    manager.unsubscribe(cb3, PROP1);
+    assertLastUnsubscribedProperty(PROP1);
     ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
 
-    ASSERT_FALSE(manager.unsubscribe(cb3, PROP2));
+    manager.unsubscribe(cb3, PROP2);
+    assertOnPropertyUnsubscribedNotCalled();
     ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2()));
 
     // The last client unsubscribed from this property.
-    ASSERT_TRUE(manager.unsubscribe(cb2, PROP2));
+    manager.unsubscribe(cb2, PROP2);
+    assertLastUnsubscribedProperty(PROP2);
 
-    // No one was subscribed, return false.
-    ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+    // No one subscribed anymore
+    manager.unsubscribe(cb1, PROP1);
+    assertLastUnsubscribedProperty(PROP1);
 }
 
 }  // namespace anonymous
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
deleted file mode 100644
index ab0f308..0000000
--- a/benchmarks/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
-    "msgq/1.0",
-]
diff --git a/benchmarks/msgq/1.0/Android.bp b/benchmarks/msgq/1.0/Android.bp
deleted file mode 100644
index 7f8ea99..0000000
--- a/benchmarks/msgq/1.0/Android.bp
+++ /dev/null
@@ -1,59 +0,0 @@
-// This file is autogenerated by hidl-gen. Do not edit manually.
-
-filegroup {
-    name: "android.hardware.benchmarks.msgq@1.0_hal",
-    srcs: [
-        "IBenchmarkMsgQ.hal",
-    ],
-}
-
-genrule {
-    name: "android.hardware.benchmarks.msgq@1.0_genc++",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.benchmarks.msgq@1.0",
-    srcs: [
-        ":android.hardware.benchmarks.msgq@1.0_hal",
-    ],
-    out: [
-        "android/hardware/benchmarks/msgq/1.0/BenchmarkMsgQAll.cpp",
-    ],
-}
-
-genrule {
-    name: "android.hardware.benchmarks.msgq@1.0_genc++_headers",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.benchmarks.msgq@1.0",
-    srcs: [
-        ":android.hardware.benchmarks.msgq@1.0_hal",
-    ],
-    out: [
-        "android/hardware/benchmarks/msgq/1.0/IBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/IHwBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/BnHwBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/BpHwBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/BsBenchmarkMsgQ.h",
-    ],
-}
-
-cc_library_shared {
-    name: "android.hardware.benchmarks.msgq@1.0",
-    generated_sources: ["android.hardware.benchmarks.msgq@1.0_genc++"],
-    generated_headers: ["android.hardware.benchmarks.msgq@1.0_genc++_headers"],
-    export_generated_headers: ["android.hardware.benchmarks.msgq@1.0_genc++_headers"],
-    shared_libs: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "liblog",
-        "libutils",
-        "libcutils",
-        "android.hidl.base@1.0",
-    ],
-    export_shared_lib_headers: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "libutils",
-        "android.hidl.base@1.0",
-    ],
-}
diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp
index fb20195..e04c2f4 100644
--- a/bluetooth/1.0/default/Android.bp
+++ b/bluetooth/1.0/default/Android.bp
@@ -56,6 +56,9 @@
     name: "android.hardware.bluetooth-hci",
     srcs: [
         "hci_packetizer.cc",
+        "hci_protocol.cc",
+        "h4_protocol.cc",
+        "mct_protocol.cc",
     ],
     export_include_dirs: ["."],
     shared_libs: [
@@ -71,16 +74,21 @@
     name: "bluetooth-vendor-interface-unit-tests",
     srcs: [
         "test/async_fd_watcher_unittest.cc",
+        "test/h4_protocol_unittest.cc",
+        "test/mct_protocol_unittest.cc",
     ],
     local_include_dirs: [
         "test",
     ],
     shared_libs: [
         "libbase",
+        "libhidlbase",
         "liblog",
     ],
     static_libs: [
         "android.hardware.bluetooth-async",
+        "android.hardware.bluetooth-hci",
+        "libgmock",
     ],
 }
 
diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc
index 287d007..2f23a69 100644
--- a/bluetooth/1.0/default/async_fd_watcher.cc
+++ b/bluetooth/1.0/default/async_fd_watcher.cc
@@ -19,6 +19,7 @@
 #include <algorithm>
 #include <atomic>
 #include <condition_variable>
+#include <map>
 #include <mutex>
 #include <thread>
 #include <vector>
@@ -26,6 +27,8 @@
 #include "sys/select.h"
 #include "unistd.h"
 
+static const int INVALID_FD = -1;
+
 namespace android {
 namespace hardware {
 namespace bluetooth {
@@ -36,8 +39,7 @@
   // Add file descriptor and callback
   {
     std::unique_lock<std::mutex> guard(internal_mutex_);
-    read_fd_ = file_descriptor;
-    cb_ = on_read_fd_ready_callback;
+    watched_fds_[file_descriptor] = on_read_fd_ready_callback;
   }
 
   // Start the thread if not started yet
@@ -58,7 +60,7 @@
   return 0;
 }
 
-void AsyncFdWatcher::StopWatchingFileDescriptor() { stopThread(); }
+void AsyncFdWatcher::StopWatchingFileDescriptors() { stopThread(); }
 
 AsyncFdWatcher::~AsyncFdWatcher() {}
 
@@ -90,8 +92,7 @@
 
   {
     std::unique_lock<std::mutex> guard(internal_mutex_);
-    cb_ = nullptr;
-    read_fd_ = -1;
+    watched_fds_.clear();
   }
 
   {
@@ -115,7 +116,11 @@
     fd_set read_fds;
     FD_ZERO(&read_fds);
     FD_SET(notification_listen_fd_, &read_fds);
-    FD_SET(read_fd_, &read_fds);
+    int max_read_fd = INVALID_FD;
+    for (auto& it : watched_fds_) {
+      FD_SET(it.first, &read_fds);
+      max_read_fd = std::max(max_read_fd, it.first);
+    }
 
     struct timeval timeout;
     struct timeval* timeout_ptr = NULL;
@@ -126,7 +131,7 @@
     }
 
     // Wait until there is data available to read on some FD.
-    int nfds = std::max(notification_listen_fd_, read_fd_);
+    int nfds = std::max(notification_listen_fd_, max_read_fd);
     int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr);
 
     // There was some error.
@@ -153,10 +158,21 @@
       continue;
     }
 
-    // Invoke the data ready callback if appropriate.
-    if (FD_ISSET(read_fd_, &read_fds)) {
+    // Invoke the data ready callbacks if appropriate.
+    std::vector<decltype(watched_fds_)::value_type> saved_callbacks;
+    {
       std::unique_lock<std::mutex> guard(internal_mutex_);
-      if (cb_) cb_(read_fd_);
+      for (auto& it : watched_fds_) {
+        if (FD_ISSET(it.first, &read_fds)) {
+          saved_callbacks.push_back(it);
+        }
+      }
+    }
+
+    for (auto& it : saved_callbacks) {
+      if (it.second) {
+        it.second(it.first);
+      }
     }
   }
 }
diff --git a/bluetooth/1.0/default/async_fd_watcher.h b/bluetooth/1.0/default/async_fd_watcher.h
index 3f7ff54..358cbc3 100644
--- a/bluetooth/1.0/default/async_fd_watcher.h
+++ b/bluetooth/1.0/default/async_fd_watcher.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <map>
 #include <mutex>
 #include <thread>
 
@@ -36,7 +37,7 @@
                                  const ReadCallback& on_read_fd_ready_callback);
   int ConfigureTimeout(const std::chrono::milliseconds timeout,
                        const TimeoutCallback& on_timeout_callback);
-  void StopWatchingFileDescriptor();
+  void StopWatchingFileDescriptors();
 
  private:
   AsyncFdWatcher(const AsyncFdWatcher&) = delete;
@@ -52,10 +53,9 @@
   std::mutex internal_mutex_;
   std::mutex timeout_mutex_;
 
-  int read_fd_;
+  std::map<int, ReadCallback> watched_fds_;
   int notification_listen_fd_;
   int notification_write_fd_;
-  ReadCallback cb_;
   TimeoutCallback timeout_cb_;
   std::chrono::milliseconds timeout_ms_;
 };
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index 1d6e600..5a282bf 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -44,21 +44,14 @@
         event_cb_->initializationComplete(
             status ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
       },
-      [this](HciPacketType type, const hidl_vec<uint8_t>& packet) {
-        switch (type) {
-          case HCI_PACKET_TYPE_EVENT:
-            event_cb_->hciEventReceived(packet);
-            break;
-          case HCI_PACKET_TYPE_ACL_DATA:
-            event_cb_->aclDataReceived(packet);
-            break;
-          case HCI_PACKET_TYPE_SCO_DATA:
-            event_cb_->scoDataReceived(packet);
-            break;
-          default:
-            ALOGE("%s Unexpected event type %d", __func__, type);
-            break;
-        }
+      [this](const hidl_vec<uint8_t>& packet) {
+        event_cb_->hciEventReceived(packet);
+      },
+      [this](const hidl_vec<uint8_t>& packet) {
+        event_cb_->aclDataReceived(packet);
+      },
+      [this](const hidl_vec<uint8_t>& packet) {
+        event_cb_->scoDataReceived(packet);
       });
   if (!rc) event_cb_->initializationComplete(Status::INITIALIZATION_ERROR);
   return Void();
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
new file mode 100644
index 0000000..8f24b5e
--- /dev/null
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -0,0 +1,71 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "h4_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth-hci-h4"
+#include <android-base/logging.h>
+#include <assert.h>
+#include <fcntl.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+  int rv = WriteSafely(uart_fd_, &type, sizeof(type));
+  if (rv == sizeof(type)) {
+    rv = WriteSafely(uart_fd_, data, length);
+  }
+  return rv;
+}
+
+void H4Protocol::OnPacketReady() {
+  switch (hci_packet_type_) {
+    case HCI_PACKET_TYPE_EVENT:
+      event_cb_(hci_packetizer_.GetPacket());
+      break;
+    case HCI_PACKET_TYPE_ACL_DATA:
+      acl_cb_(hci_packetizer_.GetPacket());
+      break;
+    case HCI_PACKET_TYPE_SCO_DATA:
+      sco_cb_(hci_packetizer_.GetPacket());
+      break;
+    default: {
+      bool bad_packet_type = true;
+      CHECK(!bad_packet_type);
+    }
+  }
+  // Get ready for the next type byte.
+  hci_packet_type_ = HCI_PACKET_TYPE_UNKNOWN;
+}
+
+void H4Protocol::OnDataReady(int fd) {
+  if (hci_packet_type_ == HCI_PACKET_TYPE_UNKNOWN) {
+    uint8_t buffer[1] = {0};
+    size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
+    CHECK(bytes_read == 1);
+    hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
+  } else {
+    hci_packetizer_.OnDataReady(fd, hci_packet_type_);
+  }
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/h4_protocol.h b/bluetooth/1.0/default/h4_protocol.h
new file mode 100644
index 0000000..0d0a1ca
--- /dev/null
+++ b/bluetooth/1.0/default/h4_protocol.h
@@ -0,0 +1,61 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <hidl/HidlSupport.h>
+
+#include "async_fd_watcher.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_protocol.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+class H4Protocol : public HciProtocol {
+ public:
+  H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
+             PacketReadCallback sco_cb)
+      : uart_fd_(fd),
+        event_cb_(event_cb),
+        acl_cb_(acl_cb),
+        sco_cb_(sco_cb),
+        hci_packetizer_([this]() { OnPacketReady(); }) {}
+
+  size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+  void OnPacketReady();
+
+  void OnDataReady(int fd);
+
+ private:
+  int uart_fd_;
+
+  PacketReadCallback event_cb_;
+  PacketReadCallback acl_cb_;
+  PacketReadCallback sco_cb_;
+
+  HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
+  hci::HciPacketizer hci_packetizer_;
+};
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 1a50196..9549858 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -18,7 +18,6 @@
 
 #define LOG_TAG "android.hardware.bluetooth.hci_packetizer"
 #include <android-base/logging.h>
-#include <cutils/properties.h>
 #include <utils/Log.h>
 
 #include <dlfcn.h>
@@ -46,63 +45,40 @@
 namespace bluetooth {
 namespace hci {
 
-HciPacketType HciPacketizer::GetPacketType() const {
-  return hci_packet_type_;
-}
+const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
 
-const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const {
-  return hci_packet_;
-}
-
-void HciPacketizer::OnDataReady(int fd) {
-  switch (hci_parser_state_) {
-    case HCI_IDLE: {
-      uint8_t buffer[1] = {0};
-      size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
-      CHECK(bytes_read == 1);
-      hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
-      CHECK(hci_packet_type_ >= HCI_PACKET_TYPE_ACL_DATA &&
-            hci_packet_type_ <= HCI_PACKET_TYPE_EVENT)
-          << "buffer[0] = " << static_cast<unsigned int>(buffer[0]);
-      hci_parser_state_ = HCI_TYPE_READY;
-      hci_packet_bytes_remaining_ = preamble_size_for_type[hci_packet_type_];
-      hci_packet_bytes_read_ = 0;
-      break;
-    }
-
-    case HCI_TYPE_READY: {
+void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
+  switch (state_) {
+    case HCI_PREAMBLE: {
       size_t bytes_read = TEMP_FAILURE_RETRY(
-          read(fd, hci_packet_preamble_ + hci_packet_bytes_read_,
-               hci_packet_bytes_remaining_));
+          read(fd, preamble_ + bytes_read_,
+               preamble_size_for_type[packet_type] - bytes_read_));
       CHECK(bytes_read > 0);
-      hci_packet_bytes_remaining_ -= bytes_read;
-      hci_packet_bytes_read_ += bytes_read;
-      if (hci_packet_bytes_remaining_ == 0) {
+      bytes_read_ += bytes_read;
+      if (bytes_read_ == preamble_size_for_type[packet_type]) {
         size_t packet_length =
-            HciGetPacketLengthForType(hci_packet_type_, hci_packet_preamble_);
-        hci_packet_.resize(preamble_size_for_type[hci_packet_type_] +
-                           packet_length);
-        memcpy(hci_packet_.data(), hci_packet_preamble_,
-               preamble_size_for_type[hci_packet_type_]);
-        hci_packet_bytes_remaining_ = packet_length;
-        hci_parser_state_ = HCI_PAYLOAD;
-        hci_packet_bytes_read_ = 0;
+            HciGetPacketLengthForType(packet_type, preamble_);
+        packet_.resize(preamble_size_for_type[packet_type] + packet_length);
+        memcpy(packet_.data(), preamble_, preamble_size_for_type[packet_type]);
+        bytes_remaining_ = packet_length;
+        state_ = HCI_PAYLOAD;
+        bytes_read_ = 0;
       }
       break;
     }
 
     case HCI_PAYLOAD: {
-      size_t bytes_read = TEMP_FAILURE_RETRY(
-          read(fd,
-               hci_packet_.data() + preamble_size_for_type[hci_packet_type_] +
-                   hci_packet_bytes_read_,
-               hci_packet_bytes_remaining_));
+      size_t bytes_read = TEMP_FAILURE_RETRY(read(
+          fd,
+          packet_.data() + preamble_size_for_type[packet_type] + bytes_read_,
+          bytes_remaining_));
       CHECK(bytes_read > 0);
-      hci_packet_bytes_remaining_ -= bytes_read;
-      hci_packet_bytes_read_ += bytes_read;
-      if (hci_packet_bytes_remaining_ == 0) {
-        hci_packet_ready_cb_();
-        hci_parser_state_ = HCI_IDLE;
+      bytes_remaining_ -= bytes_read;
+      bytes_read_ += bytes_read;
+      if (bytes_remaining_ == 0) {
+        packet_ready_cb_();
+        state_ = HCI_PREAMBLE;
+        bytes_read_ = 0;
       }
       break;
     }
diff --git a/bluetooth/1.0/default/hci_packetizer.h b/bluetooth/1.0/default/hci_packetizer.h
index e9c01dc..90579bd 100644
--- a/bluetooth/1.0/default/hci_packetizer.h
+++ b/bluetooth/1.0/default/hci_packetizer.h
@@ -32,20 +32,19 @@
 
 class HciPacketizer {
  public:
-  HciPacketizer(HciPacketReadyCallback packet_cb) : hci_packet_ready_cb_(packet_cb) {};
-  void OnDataReady(int fd);
+  HciPacketizer(HciPacketReadyCallback packet_cb)
+      : packet_ready_cb_(packet_cb){};
+  void OnDataReady(int fd, HciPacketType packet_type);
   const hidl_vec<uint8_t>& GetPacket() const;
-  HciPacketType GetPacketType() const;
 
  protected:
-  enum HciParserState { HCI_IDLE, HCI_TYPE_READY, HCI_PAYLOAD };
-  HciParserState hci_parser_state_{HCI_IDLE};
-  HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
-  uint8_t hci_packet_preamble_[HCI_PREAMBLE_SIZE_MAX];
-  hidl_vec<uint8_t> hci_packet_;
-  size_t hci_packet_bytes_remaining_;
-  size_t hci_packet_bytes_read_;
-  HciPacketReadyCallback hci_packet_ready_cb_;
+  enum State { HCI_PREAMBLE, HCI_PAYLOAD };
+  State state_{HCI_PREAMBLE};
+  uint8_t preamble_[HCI_PREAMBLE_SIZE_MAX];
+  hidl_vec<uint8_t> packet_;
+  size_t bytes_remaining_{0};
+  size_t bytes_read_{0};
+  HciPacketReadyCallback packet_ready_cb_;
 };
 
 }  // namespace hci
diff --git a/bluetooth/1.0/default/hci_protocol.cc b/bluetooth/1.0/default/hci_protocol.cc
new file mode 100644
index 0000000..cd709b4
--- /dev/null
+++ b/bluetooth/1.0/default/hci_protocol.cc
@@ -0,0 +1,74 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "hci_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth-hci-hci_protocol"
+#include <android-base/logging.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+namespace {
+
+const size_t preamble_size_for_type[] = {
+    0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
+    HCI_EVENT_PREAMBLE_SIZE};
+const size_t packet_length_offset_for_type[] = {
+    0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO,
+    HCI_LENGTH_OFFSET_EVT};
+
+size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) {
+  size_t offset = packet_length_offset_for_type[type];
+  if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset];
+  return (((preamble[offset + 1]) << 8) | preamble[offset]);
+}
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+size_t HciProtocol::WriteSafely(int fd, const uint8_t* data, size_t length) {
+  size_t transmitted_length = 0;
+  while (length > 0) {
+    ssize_t ret =
+        TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
+
+    if (ret == -1) {
+      if (errno == EAGAIN) continue;
+      ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+      break;
+
+    } else if (ret == 0) {
+      // Nothing written :(
+      ALOGE("%s zero bytes written - something went wrong...", __func__);
+      break;
+    }
+
+    transmitted_length += ret;
+    length -= ret;
+  }
+
+  return transmitted_length;
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/hci_protocol.h b/bluetooth/1.0/default/hci_protocol.h
new file mode 100644
index 0000000..6821107
--- /dev/null
+++ b/bluetooth/1.0/default/hci_protocol.h
@@ -0,0 +1,49 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <hidl/HidlSupport.h>
+
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_packetizer.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+using ::android::hardware::hidl_vec;
+using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
+
+// Implementation of HCI protocol bits common to different transports
+class HciProtocol {
+ public:
+  HciProtocol() = default;
+  virtual ~HciProtocol(){};
+
+  // Protocol-specific implementation of sending packets.
+  virtual size_t Send(uint8_t type, const uint8_t* data, size_t length) = 0;
+
+ protected:
+  static size_t WriteSafely(int fd, const uint8_t* data, size_t length);
+};
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/mct_protocol.cc b/bluetooth/1.0/default/mct_protocol.cc
new file mode 100644
index 0000000..813cebd
--- /dev/null
+++ b/bluetooth/1.0/default/mct_protocol.cc
@@ -0,0 +1,71 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "mct_protocol.h"
+
+#include <assert.h>
+
+#define LOG_TAG "android.hardware.bluetooth-hci-mct"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include <fcntl.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+MctProtocol::MctProtocol(int* fds, PacketReadCallback event_cb,
+                         PacketReadCallback acl_cb)
+    : event_cb_(event_cb),
+      acl_cb_(acl_cb),
+      event_packetizer_([this]() { OnEventPacketReady(); }),
+      acl_packetizer_([this]() { OnAclDataPacketReady(); }) {
+  for (int i = 0; i < CH_MAX; i++) {
+    uart_fds_[i] = fds[i];
+  }
+}
+
+size_t MctProtocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+  if (type == HCI_PACKET_TYPE_COMMAND)
+    return WriteSafely(uart_fds_[CH_CMD], data, length);
+  if (type == HCI_PACKET_TYPE_ACL_DATA)
+    return WriteSafely(uart_fds_[CH_ACL_OUT], data, length);
+  CHECK(type == HCI_PACKET_TYPE_COMMAND || type == HCI_PACKET_TYPE_ACL_DATA);
+  return 0;
+}
+
+void MctProtocol::OnEventPacketReady() {
+  event_cb_(event_packetizer_.GetPacket());
+}
+
+void MctProtocol::OnAclDataPacketReady() {
+  acl_cb_(acl_packetizer_.GetPacket());
+}
+
+void MctProtocol::OnEventDataReady(int fd) {
+  event_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_EVENT);
+}
+
+void MctProtocol::OnAclDataReady(int fd) {
+  acl_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_ACL_DATA);
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/mct_protocol.h b/bluetooth/1.0/default/mct_protocol.h
new file mode 100644
index 0000000..6991746
--- /dev/null
+++ b/bluetooth/1.0/default/mct_protocol.h
@@ -0,0 +1,56 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <hidl/HidlSupport.h>
+
+#include "async_fd_watcher.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_protocol.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+class MctProtocol : public HciProtocol {
+ public:
+  MctProtocol(int* fds, PacketReadCallback event_cb, PacketReadCallback acl_cb);
+
+  size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+  void OnEventPacketReady();
+  void OnAclDataPacketReady();
+
+  void OnEventDataReady(int fd);
+  void OnAclDataReady(int fd);
+
+ private:
+  int uart_fds_[CH_MAX];
+
+  PacketReadCallback event_cb_;
+  PacketReadCallback acl_cb_;
+
+  hci::HciPacketizer event_packetizer_;
+  hci::HciPacketizer acl_packetizer_;
+};
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
index a7f5bda..b0c533c 100644
--- a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
+++ b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+#define LOG_TAG "async_fd_watcher_unittest"
+
 #include "async_fd_watcher.h"
 #include <gtest/gtest.h>
 #include <cstdint>
@@ -122,8 +124,8 @@
   }
 
   void CleanUpServer() {
-    async_fd_watcher_.StopWatchingFileDescriptor();
-    conn_watcher_.StopWatchingFileDescriptor();
+    async_fd_watcher_.StopWatchingFileDescriptors();
+    conn_watcher_.StopWatchingFileDescriptors();
     close(socket_fd_);
   }
 
@@ -211,7 +213,7 @@
   });
 
   ConnectClient();
-  conn_watcher.StopWatchingFileDescriptor();
+  conn_watcher.StopWatchingFileDescriptors();
   close(socket_fd);
 }
 
@@ -233,7 +235,7 @@
   EXPECT_FALSE(timed_out);
   sleep(1);
   EXPECT_TRUE(timed_out);
-  conn_watcher.StopWatchingFileDescriptor();
+  conn_watcher.StopWatchingFileDescriptors();
   close(socket_fd);
 }
 
@@ -265,10 +267,64 @@
   sleep(1);
   EXPECT_TRUE(timed_out);
   EXPECT_TRUE(timed_out2);
-  conn_watcher.StopWatchingFileDescriptor();
+  conn_watcher.StopWatchingFileDescriptors();
   close(socket_fd);
 }
 
+// Use a single AsyncFdWatcher to watch two file descriptors.
+TEST_F(AsyncFdWatcherSocketTest, WatchTwoFileDescriptors) {
+  int sockfd[2];
+  socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+  bool cb1_called = false;
+  bool* cb1_called_ptr = &cb1_called;
+  bool cb2_called = false;
+  bool* cb2_called_ptr = &cb2_called;
+
+  AsyncFdWatcher watcher;
+  watcher.WatchFdForNonBlockingReads(sockfd[0], [cb1_called_ptr](int fd) {
+    char read_buf[1] = {0};
+    int n = TEMP_FAILURE_RETRY(read(fd, read_buf, sizeof(read_buf)));
+    ASSERT_TRUE(n == sizeof(read_buf));
+    ASSERT_TRUE(read_buf[0] == '1');
+    *cb1_called_ptr = true;
+  });
+
+  watcher.WatchFdForNonBlockingReads(sockfd[1], [cb2_called_ptr](int fd) {
+    char read_buf[1] = {0};
+    int n = TEMP_FAILURE_RETRY(read(fd, read_buf, sizeof(read_buf)));
+    ASSERT_TRUE(n == sizeof(read_buf));
+    ASSERT_TRUE(read_buf[0] == '2');
+    *cb2_called_ptr = true;
+  });
+
+  // Fail if the test doesn't pass within 3 seconds
+  watcher.ConfigureTimeout(std::chrono::seconds(3), [this]() {
+    bool connection_timeout = true;
+    ASSERT_FALSE(connection_timeout);
+  });
+
+  EXPECT_FALSE(cb1_called);
+  EXPECT_FALSE(cb2_called);
+
+  char one_buf[1] = {'1'};
+  TEMP_FAILURE_RETRY(write(sockfd[1], one_buf, sizeof(one_buf)));
+
+  sleep(1);
+
+  EXPECT_TRUE(cb1_called);
+  EXPECT_FALSE(cb2_called);
+
+  char two_buf[1] = {'2'};
+  TEMP_FAILURE_RETRY(write(sockfd[0], two_buf, sizeof(two_buf)));
+
+  sleep(1);
+
+  EXPECT_TRUE(cb1_called);
+  EXPECT_TRUE(cb2_called);
+
+  watcher.StopWatchingFileDescriptors();
+}
+
 // Use two AsyncFdWatchers to set up a server socket.
 TEST_F(AsyncFdWatcherSocketTest, ClientServer) {
   ConfigureServer();
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
new file mode 100644
index 0000000..d53aaa9
--- /dev/null
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -0,0 +1,213 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "bt_h4_unittest"
+
+#include "h4_protocol.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <mutex>
+#include <vector>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::testing::Eq;
+using hci::H4Protocol;
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char acl_data[100] =
+    "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] =
+    "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+
+MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
+  size_t length = strlen(payload) + preamble_length;
+  if (length != arg.size()) {
+    return false;
+  }
+
+  if (memcmp(preamble, arg.data(), preamble_length) != 0) {
+    return false;
+  }
+
+  return memcmp(payload, arg.data() + preamble_length,
+                length - preamble_length) == 0;
+};
+
+ACTION_P2(Notify, mutex, condition) {
+  ALOGD("%s", __func__);
+  std::unique_lock<std::mutex> lock(*mutex);
+  condition->notify_one();
+}
+
+class H4ProtocolTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ALOGD("%s", __func__);
+
+    int sockfd[2];
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+    H4Protocol* h4_hci =
+        new H4Protocol(sockfd[0], event_cb_.AsStdFunction(),
+                       acl_cb_.AsStdFunction(), sco_cb_.AsStdFunction());
+    fd_watcher_.WatchFdForNonBlockingReads(
+        sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+    protocol_ = h4_hci;
+
+    fake_uart_ = sockfd[1];
+  }
+
+  void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+  void SendAndReadUartOutbound(uint8_t type, char* data) {
+    ALOGD("%s sending", __func__);
+    int data_length = strlen(data);
+    protocol_->Send(type, (uint8_t*)data, data_length);
+
+    int uart_length = data_length + 1;  // + 1 for data type code
+    int i;
+
+    ALOGD("%s reading", __func__);
+    for (i = 0; i < uart_length; i++) {
+      fd_set read_fds;
+      FD_ZERO(&read_fds);
+      FD_SET(fake_uart_, &read_fds);
+      TEMP_FAILURE_RETRY(select(fake_uart_ + 1, &read_fds, NULL, NULL, NULL));
+
+      char byte;
+      TEMP_FAILURE_RETRY(read(fake_uart_, &byte, 1));
+
+      EXPECT_EQ(i == 0 ? type : data[i - 1], byte);
+    }
+
+    EXPECT_EQ(i, uart_length);
+  }
+
+  void WriteAndExpectInboundAclData(char* payload) {
+    // h4 type[1] + handle[2] + size[2]
+    char preamble[5] = {HCI_PACKET_TYPE_ACL_DATA, 19, 92, 0, 0};
+    int length = strlen(payload);
+    preamble[3] = length & 0xFF;
+    preamble[4] = (length >> 8) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(acl_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+                                             payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  void WriteAndExpectInboundScoData(char* payload) {
+    // h4 type[1] + handle[2] + size[1]
+    char preamble[4] = {HCI_PACKET_TYPE_SCO_DATA, 20, 17, 0};
+    preamble[3] = strlen(payload) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(sco_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+                                             payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  void WriteAndExpectInboundEvent(char* payload) {
+    // h4 type[1] + event_code[1] + size[1]
+    char preamble[3] = {HCI_PACKET_TYPE_EVENT, 9, 0};
+    preamble[2] = strlen(payload) & 0xFF;
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(event_cb_, Call(HidlVecMatches(preamble + 1,
+                                               sizeof(preamble) - 1, payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait(lock);
+    }
+  }
+
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> sco_cb_;
+  async::AsyncFdWatcher fd_watcher_;
+  H4Protocol* protocol_;
+  int fake_uart_;
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(H4ProtocolTest, TestSends) {
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(H4ProtocolTest, TestReads) {
+  WriteAndExpectInboundAclData(acl_data);
+  WriteAndExpectInboundScoData(sco_data);
+  WriteAndExpectInboundEvent(event_data);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/test/mct_protocol_unittest.cc b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
new file mode 100644
index 0000000..5751a5e
--- /dev/null
+++ b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
@@ -0,0 +1,200 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "bt_h4_unittest"
+
+#include "mct_protocol.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <mutex>
+#include <vector>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::testing::Eq;
+using hci::MctProtocol;
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char acl_data[100] =
+    "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] =
+    "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+
+MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
+  size_t length = strlen(payload) + preamble_length;
+  if (length != arg.size()) {
+    return false;
+  }
+
+  if (memcmp(preamble, arg.data(), preamble_length) != 0) {
+    return false;
+  }
+
+  return memcmp(payload, arg.data() + preamble_length,
+                length - preamble_length) == 0;
+};
+
+ACTION_P2(Notify, mutex, condition) {
+  ALOGD("%s", __func__);
+  std::unique_lock<std::mutex> lock(*mutex);
+  condition->notify_one();
+}
+
+class MctProtocolTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ALOGD("%s", __func__);
+
+    int mct_fds[CH_MAX];
+    MakeFakeUartFd(CH_CMD, mct_fds, fake_uart_);
+    MakeFakeUartFd(CH_EVT, mct_fds, fake_uart_);
+    MakeFakeUartFd(CH_ACL_IN, mct_fds, fake_uart_);
+    MakeFakeUartFd(CH_ACL_OUT, mct_fds, fake_uart_);
+
+    MctProtocol* mct_hci = new MctProtocol(mct_fds, event_cb_.AsStdFunction(),
+                                           acl_cb_.AsStdFunction());
+    fd_watcher_.WatchFdForNonBlockingReads(
+        mct_fds[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+    fd_watcher_.WatchFdForNonBlockingReads(
+        mct_fds[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+    protocol_ = mct_hci;
+  }
+
+  void MakeFakeUartFd(int index, int* host_side, int* controller_side) {
+    int sockfd[2];
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+    host_side[index] = sockfd[0];
+    controller_side[index] = sockfd[1];
+  }
+
+  void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+  void SendAndReadUartOutbound(uint8_t type, char* data, int outbound_fd) {
+    ALOGD("%s sending", __func__);
+    int data_length = strlen(data);
+    protocol_->Send(type, (uint8_t*)data, data_length);
+
+    ALOGD("%s reading", __func__);
+    int i;
+    for (i = 0; i < data_length; i++) {
+      fd_set read_fds;
+      FD_ZERO(&read_fds);
+      FD_SET(outbound_fd, &read_fds);
+      TEMP_FAILURE_RETRY(select(outbound_fd + 1, &read_fds, NULL, NULL, NULL));
+
+      char byte;
+      TEMP_FAILURE_RETRY(read(outbound_fd, &byte, 1));
+
+      EXPECT_EQ(data[i], byte);
+    }
+
+    EXPECT_EQ(i, data_length);
+  }
+
+  void WriteAndExpectInboundAclData(char* payload) {
+    // handle[2] + size[2]
+    char preamble[4] = {19, 92, 0, 0};
+    int length = strlen(payload);
+    preamble[2] = length & 0xFF;
+    preamble[3] = (length >> 8) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(
+        write(fake_uart_[CH_ACL_IN], preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_[CH_ACL_IN], payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(acl_cb_,
+                Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  void WriteAndExpectInboundEvent(char* payload) {
+    // event_code[1] + size[1]
+    char preamble[2] = {9, 0};
+    preamble[1] = strlen(payload) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(event_cb_,
+                Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
+  async::AsyncFdWatcher fd_watcher_;
+  MctProtocol* protocol_;
+  int fake_uart_[CH_MAX];
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(MctProtocolTest, TestSends) {
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1,
+                          fake_uart_[CH_CMD]);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2,
+                          fake_uart_[CH_ACL_OUT]);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(MctProtocolTest, TestReads) {
+  WriteAndExpectInboundAclData(acl_data);
+  WriteAndExpectInboundEvent(event_data);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 3878129..6d3b56f 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -27,6 +27,8 @@
 #include <fcntl.h>
 
 #include "bluetooth_address.h"
+#include "h4_protocol.h"
+#include "mct_protocol.h"
 
 static const char* VENDOR_LIBRARY_NAME = "libbt-vendor.so";
 static const char* VENDOR_LIBRARY_SYMBOL_NAME =
@@ -64,30 +66,6 @@
   return packet;
 }
 
-size_t write_safely(int fd, const uint8_t* data, size_t length) {
-  size_t transmitted_length = 0;
-  while (length > 0) {
-    ssize_t ret =
-        TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
-
-    if (ret == -1) {
-      if (errno == EAGAIN) continue;
-      ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
-      break;
-
-    } else if (ret == 0) {
-      // Nothing written :(
-      ALOGE("%s zero bytes written - something went wrong...", __func__);
-      break;
-    }
-
-    transmitted_length += ret;
-    length -= ret;
-  }
-
-  return transmitted_length;
-}
-
 bool internal_command_event_match(const hidl_vec<uint8_t>& packet) {
   uint8_t event_code = packet[0];
   if (event_code != HCI_COMMAND_COMPLETE_EVENT) {
@@ -185,10 +163,12 @@
 
 bool VendorInterface::Initialize(
     InitializeCompleteCallback initialize_complete_cb,
-    PacketReadCallback packet_read_cb) {
+    PacketReadCallback event_cb, PacketReadCallback acl_cb,
+    PacketReadCallback sco_cb) {
   assert(!g_vendor_interface);
   g_vendor_interface = new VendorInterface();
-  return g_vendor_interface->Open(initialize_complete_cb, packet_read_cb);
+  return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
+                                  sco_cb);
 }
 
 void VendorInterface::Shutdown() {
@@ -201,9 +181,10 @@
 VendorInterface* VendorInterface::get() { return g_vendor_interface; }
 
 bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
-                           PacketReadCallback packet_read_cb) {
+                           PacketReadCallback event_cb,
+                           PacketReadCallback acl_cb,
+                           PacketReadCallback sco_cb) {
   initialize_complete_cb_ = initialize_complete_cb;
-  packet_read_cb_ = packet_read_cb;
 
   // Initialize vendor interface
 
@@ -241,28 +222,41 @@
   power_state = BT_VND_PWR_ON;
   lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
 
-  // Get the UART socket
+  // Get the UART socket(s)
 
   int fd_list[CH_MAX] = {0};
   int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
 
-  if (fd_count != 1) {
-    ALOGE("%s fd count %d != 1; we can't handle this currently...", __func__,
-          fd_count);
-    return false;
+  for (int i = 0; i < fd_count; i++) {
+    if (fd_list[i] == INVALID_FD) {
+      ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
+      return false;
+    }
   }
 
-  uart_fd_ = fd_list[0];
-  if (uart_fd_ == INVALID_FD) {
-    ALOGE("%s unable to determine UART fd", __func__);
-    return false;
+  event_cb_ = event_cb;
+  PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
+    HandleIncomingEvent(event);
+  };
+
+  if (fd_count == 1) {
+    hci::H4Protocol* h4_hci =
+        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb);
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+    hci_ = h4_hci;
+  } else {
+    hci::MctProtocol* mct_hci =
+        new hci::MctProtocol(fd_list, intercept_events, acl_cb);
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+    if (fd_count >= CH_ACL_IN)
+      fd_watcher_.WatchFdForNonBlockingReads(
+          fd_list[CH_ACL_IN],
+          [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+    hci_ = mct_hci;
   }
 
-  ALOGI("%s UART fd: %d", __func__, uart_fd_);
-
-  fd_watcher_.WatchFdForNonBlockingReads(uart_fd_,
-                                         [this](int fd) { hci_packetizer_.OnDataReady(fd); });
-
   // Initially, the power management is off.
   lpm_wake_deasserted = true;
 
@@ -274,14 +268,18 @@
 }
 
 void VendorInterface::Close() {
-  fd_watcher_.StopWatchingFileDescriptor();
+  fd_watcher_.StopWatchingFileDescriptors();
+
+  if (hci_ != nullptr) {
+    delete hci_;
+    hci_ = nullptr;
+  }
 
   if (lib_interface_ != nullptr) {
     bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
     lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
 
     lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
-    uart_fd_ = INVALID_FD;
     int power_state = BT_VND_PWR_OFF;
     lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
   }
@@ -298,8 +296,6 @@
 }
 
 size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
-  if (uart_fd_ == INVALID_FD) return 0;
-
   recent_activity_flag = true;
 
   if (lpm_wake_deasserted == true) {
@@ -313,11 +309,7 @@
     ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
   }
 
-  int rv = write_safely(uart_fd_, &type, sizeof(type));
-  if (rv == sizeof(type))
-    rv = write_safely(uart_fd_, data, length);
-
-  return rv;
+  return hci_->Send(type, data, length);
 }
 
 void VendorInterface::OnFirmwareConfigured(uint8_t result) {
@@ -357,26 +349,18 @@
   recent_activity_flag = false;
 }
 
-void VendorInterface::OnPacketReady() {
-  VendorInterface::get()->HandleIncomingPacket();
-}
+void VendorInterface::HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet) {
+  if (internal_command.cb != nullptr &&
+      internal_command_event_match(hci_packet)) {
+    HC_BT_HDR* bt_hdr = WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);
 
-void VendorInterface::HandleIncomingPacket() {
-  HciPacketType hci_packet_type = hci_packetizer_.GetPacketType();
-  hidl_vec<uint8_t> hci_packet = hci_packetizer_.GetPacket();
-        if (internal_command.cb != nullptr &&
-            hci_packet_type == HCI_PACKET_TYPE_EVENT &&
-            internal_command_event_match(hci_packet)) {
-          HC_BT_HDR* bt_hdr =
-              WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);
-
-          // The callbacks can send new commands, so don't zero after calling.
-          tINT_CMD_CBACK saved_cb = internal_command.cb;
-          internal_command.cb = nullptr;
-          saved_cb(bt_hdr);
-        } else {
-          packet_read_cb_(hci_packet_type, hci_packet);
-        }
+    // The callbacks can send new commands, so don't zero after calling.
+    tINT_CMD_CBACK saved_cb = internal_command.cb;
+    internal_command.cb = nullptr;
+    saved_cb(bt_hdr);
+  } else {
+    event_cb_(hci_packet);
+  }
 }
 
 }  // namespace implementation
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 8115640..a401ee6 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -20,7 +20,7 @@
 
 #include "async_fd_watcher.h"
 #include "bt_vendor_lib.h"
-#include "hci_packetizer.h"
+#include "hci_protocol.h"
 
 namespace android {
 namespace hardware {
@@ -30,15 +30,15 @@
 
 using ::android::hardware::hidl_vec;
 using InitializeCompleteCallback = std::function<void(bool success)>;
-using PacketReadCallback =
-    std::function<void(HciPacketType, const hidl_vec<uint8_t> &)>;
+using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
 
 class FirmwareStartupTimer;
 
 class VendorInterface {
  public:
   static bool Initialize(InitializeCompleteCallback initialize_complete_cb,
-                         PacketReadCallback packet_read_cb);
+                         PacketReadCallback event_cb, PacketReadCallback acl_cb,
+                         PacketReadCallback sco_cb);
   static void Shutdown();
   static VendorInterface *get();
 
@@ -46,27 +46,25 @@
 
   void OnFirmwareConfigured(uint8_t result);
 
-  static void OnPacketReady();
-
  private:
   virtual ~VendorInterface() = default;
 
   bool Open(InitializeCompleteCallback initialize_complete_cb,
-            PacketReadCallback packet_read_cb);
+            PacketReadCallback event_cb, PacketReadCallback acl_cb,
+            PacketReadCallback sco_cb);
   void Close();
 
   void OnTimeout();
 
-  void HandleIncomingPacket();
+  void HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet);
 
   void *lib_handle_;
   bt_vendor_interface_t *lib_interface_;
   async::AsyncFdWatcher fd_watcher_;
-  int uart_fd_;
-  PacketReadCallback packet_read_cb_;
   InitializeCompleteCallback initialize_complete_cb_;
+  hci::HciProtocol* hci_;
 
-  hci::HciPacketizer hci_packetizer_ {VendorInterface::OnPacketReady};
+  PacketReadCallback event_cb_;
 
   FirmwareStartupTimer *firmware_startup_timer_;
 };
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
index 0e5f1fb..9d56164 100644
--- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -42,6 +42,7 @@
 using ::android::hardware::broadcastradio::V1_0::Result;
 using ::android::hardware::broadcastradio::V1_0::Class;
 using ::android::hardware::broadcastradio::V1_0::Properties;
+using ::android::hardware::broadcastradio::V1_0::Band;
 using ::android::hardware::broadcastradio::V1_0::BandConfig;
 using ::android::hardware::broadcastradio::V1_0::Direction;
 using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
@@ -83,15 +84,15 @@
             return Void();
         }
 
-        virtual Return<void> configChange(Result result, const BandConfig& config __unused) {
+        virtual Return<void> configChange(Result result, const BandConfig& config) {
             ALOGI("%s result %d", __FUNCTION__, result);
-            mParentTest->onResultCallback(result);
+            mParentTest->onConfigChangeCallback(result, config);
             return Void();
         }
 
-        virtual Return<void> tuneComplete(Result result, const ProgramInfo& info __unused) {
+        virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) {
             ALOGI("%s result %d", __FUNCTION__, result);
-            mParentTest->onResultCallback(result);
+            mParentTest->onTuneCompleteCallback(result, info);
             return Void();
         }
 
@@ -146,11 +147,22 @@
     }
 
     /**
-     * Method called by MyCallback when a callback with status is received
+     * Method called by MyCallback when configChange() callback is received.
      */
-    void onResultCallback(Result result) {
+    void onConfigChangeCallback(Result result, const BandConfig& config) {
         Mutex::Autolock _l(mLock);
         mResultCallbackData = result;
+        mBandConfigCallbackData = config;
+        onCallback_l();
+    }
+
+    /**
+     * Method called by MyCallback when tuneComplete() callback is received.
+     */
+    void onTuneCompleteCallback(Result result, const ProgramInfo& info) {
+        Mutex::Autolock _l(mLock);
+        mResultCallbackData = result;
+        mProgramInfoCallbackData = info;
         onCallback_l();
     }
 
@@ -209,6 +221,8 @@
     bool mCallbackCalled;
     bool mBoolCallbackData;
     Result mResultCallbackData;
+    ProgramInfo mProgramInfoCallbackData;
+    BandConfig mBandConfigCallbackData;
     bool mHwFailure;
 };
 
@@ -219,6 +233,35 @@
     virtual void TearDown() {}
 };
 
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+
+/**
+ * Compares two BandConfig objects for testing purposes.
+ */
+static bool operator==(const BandConfig& l, const BandConfig& r) {
+    if (l.type != r.type) return false;
+    if (l.antennaConnected != r.antennaConnected) return false;
+    if (l.lowerLimit != r.lowerLimit) return false;
+    if (l.upperLimit != r.upperLimit) return false;
+    if (l.spacings != r.spacings) return false;
+    if (l.type == Band::AM || l.type == Band::AM_HD) {
+        return l.ext.am == r.ext.am;
+    } else if (l.type == Band::FM || l.type == Band::FM_HD) {
+        return l.ext.fm == r.ext.fm;
+    } else {
+        // unsupported type
+        return false;
+    }
+}
+
+}  // V1_0
+}  // broadcastradio
+}  // hardware
+}  // android
+
 bool BroadcastRadioHidlTest::getProperties()
 {
     if (mHalProperties.bands.size() == 0) {
@@ -351,11 +394,12 @@
     ASSERT_EQ(true, openTuner());
     // test setConfiguration
     mCallbackCalled = false;
-    Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
+    Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[1]);
     EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
     EXPECT_EQ(Result::OK, mResultCallbackData);
+    EXPECT_EQ(mHalProperties.bands[1], mBandConfigCallbackData);
 
     // test getConfiguration
     BandConfig halConfig;
@@ -369,7 +413,39 @@
             });
     EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_EQ(Result::OK, halResult);
-    EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
+    EXPECT_EQ(mHalProperties.bands[1], halConfig);
+}
+
+/**
+ * Test ITuner::setConfiguration() with invalid arguments.
+ *
+ * Verifies that:
+ *  - the methods returns INVALID_ARGUMENTS on invalid arguments
+ *  - the method recovers and succeeds after passing correct arguments
+ */
+TEST_F(BroadcastRadioHidlTest, SetConfigurationFails) {
+    ASSERT_EQ(true, openTuner());
+
+    // Let's define a config that's bad for sure.
+    BandConfig badConfig = {};
+    badConfig.type = Band::FM;
+    badConfig.lowerLimit = 0xFFFFFFFF;
+    badConfig.upperLimit = 0;
+    badConfig.spacings = (std::vector<uint32_t>){ 0 };
+
+    // Test setConfiguration failing on bad data.
+    mCallbackCalled = false;
+    auto setResult = mTuner->setConfiguration(badConfig);
+    EXPECT_TRUE(setResult.isOk());
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult);
+
+    // Test setConfiguration recovering after passing good data.
+    mCallbackCalled = false;
+    setResult = mTuner->setConfiguration(mHalProperties.bands[0]);
+    EXPECT_TRUE(setResult.isOk());
+    EXPECT_EQ(Result::OK, setResult);
+    EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
+    EXPECT_EQ(Result::OK, mResultCallbackData);
 }
 
 /**
@@ -453,6 +529,7 @@
     EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
+    EXPECT_EQ(channel, mProgramInfoCallbackData.channel);
 
     // test getProgramInformation
     ProgramInfo halInfo;
@@ -481,6 +558,42 @@
     EXPECT_EQ(Result::OK, hidlResult);
 }
 
+/**
+ * Test ITuner::tune failing when channel out of the range is provided.
+ *
+ * Verifies that:
+ *  - the method returns INVALID_ARGUMENTS when applicable
+ *  - the method recovers and succeeds after passing correct arguments
+ */
+TEST_F(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
+    ASSERT_TRUE(openTuner());
+    ASSERT_TRUE(checkAntenna());
+
+    // get current channel bounds
+    BandConfig halConfig;
+    Result halResult;
+    auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+        halResult = result;
+        halConfig = config;
+    });
+    ASSERT_TRUE(configResult.isOk());
+    ASSERT_EQ(Result::OK, halResult);
+
+    // try to tune slightly above the limit and expect to fail
+    auto badChannel = halConfig.upperLimit + halConfig.spacings[0];
+    auto tuneResult = mTuner->tune(badChannel, 0);
+    EXPECT_TRUE(tuneResult.isOk());
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
+    EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+    // tuning exactly at the limit should succeed
+    auto goodChannel = halConfig.upperLimit;
+    tuneResult = mTuner->tune(goodChannel, 0);
+    EXPECT_TRUE(tuneResult.isOk());
+    EXPECT_EQ(Result::OK, tuneResult);
+    EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+}
+
 
 int main(int argc, char** argv) {
   ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
diff --git a/broadcastradio/1.1/ITuner.hal b/broadcastradio/1.1/ITuner.hal
index 72b2847..4f34019 100644
--- a/broadcastradio/1.1/ITuner.hal
+++ b/broadcastradio/1.1/ITuner.hal
@@ -19,11 +19,32 @@
 import @1.0::ITuner;
 
 interface ITuner extends @1.0::ITuner {
-    /*
+
+    /**
      * Retrieve current station information.
      * @return result OK if scan successfully started
      *                NOT_INITIALIZED if another error occurs
      * @return info Current program information.
      */
     getProgramInformation_1_1() generates(Result result, ProgramInfo info);
+
+    /**
+     * Retrieve station list.
+     *
+     * This call does not trigger actual scan, but operates on the list cached
+     * internally at the driver level.
+     *
+     * @param filter vendor-specific filter for the stations to be retrieved.
+     *               An empty string MUST result in full list.
+     *               Client application MUST verify vendor/product name
+     *               before setting this parameter to anything else.
+     * @return result OK if the list was successfully retrieved.
+     *                NOT_READY if the scan is in progress.
+     *                NOT_STARTED if the scan has not been started.
+     *                NOT_INITIALIZED if any other error occurs.
+     * @return programList List of stations available for user.
+     */
+    getProgramList(string filter)
+            generates(ProgramListResult result, vec<ProgramInfo> programList);
+
 };
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
index 6258569..b4eb184 100644
--- a/broadcastradio/1.1/default/Tuner.cpp
+++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -200,6 +200,13 @@
     return Void();
 }
 
+Return<void> Tuner::getProgramList(const hidl_string& filter __unused, getProgramList_cb _hidl_cb) {
+    hidl_vec<ProgramInfo> pList;
+    // TODO(b/34054813): do the actual implementation.
+    _hidl_cb(ProgramListResult::NOT_INITIALIZED, pList);
+    return Void();
+}
+
 } // namespace implementation
 }  // namespace V1_1
 }  // namespace broadcastradio
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h
index 1f3dc7f..fcf053a 100644
--- a/broadcastradio/1.1/default/Tuner.h
+++ b/broadcastradio/1.1/default/Tuner.h
@@ -42,6 +42,7 @@
     Return<Result> cancel() override;
     Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override;
     Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override;
+    Return<void> getProgramList(const hidl_string& filter, getProgramList_cb _hidl_cb) override;
 
     static void callback(radio_hal_event_t *halEvent, void *cookie);
     void onCallback(radio_hal_event_t *halEvent);
diff --git a/broadcastradio/1.1/types.hal b/broadcastradio/1.1/types.hal
index 38f4b39..3b212eb 100644
--- a/broadcastradio/1.1/types.hal
+++ b/broadcastradio/1.1/types.hal
@@ -20,6 +20,12 @@
 
 typedef @1.0::Result Result;
 
+enum ProgramListResult : Result {
+    NOT_READY,
+    NOT_STARTED,
+    TEMPORARILY_UNAVAILABLE,
+};
+
 enum DigitalStatus : int32_t {
     INVALID     = -1,
     UNAVAILABLE = 1,  // current program is analog-only
diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal
index c07a670..fe1edbf 100644
--- a/camera/device/3.2/types.hal
+++ b/camera/device/3.2/types.hal
@@ -161,8 +161,21 @@
      * CONSTRAINED_HIGH_SPEED_VIDEO in the android.request.availableCapabilities
      * static metadata.
      */
-    CONSTRAINED_HIGH_SPEED_MODE = 1
+    CONSTRAINED_HIGH_SPEED_MODE = 1,
 
+    /**
+     * A set of vendor-defined operating modes, for custom default camera
+     * application features that can't be implemented in the fully flexible fashion
+     * required for NORMAL_MODE.
+     */
+    VENDOR_MODE_0 = 0x8000,
+    VENDOR_MODE_1,
+    VENDOR_MODE_2,
+    VENDOR_MODE_3,
+    VENDOR_MODE_4,
+    VENDOR_MODE_5,
+    VENDOR_MODE_6,
+    VENDOR_MODE_7
 };
 
 /**
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index c5eea89..40a05e6 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -42,8 +42,6 @@
 using ::android::hardware::contexthub::V1_0::TransactionResult;
 using ::android::sp;
 
-#define CONTEXTHUB_SERVICE_NAME "contexthub"
-
 #define ASSERT_OK(result) ASSERT_EQ(result, Result::OK)
 #define EXPECT_OK(result) EXPECT_EQ(result, Result::OK)
 
@@ -80,7 +78,7 @@
   static std::vector<uint32_t> hubIds;
 
   if (hubIds.size() == 0) {
-    sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>(CONTEXTHUB_SERVICE_NAME);
+    sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>();
 
     if (hubApi != nullptr) {
       for (ContextHub hub : getHubsSync(hubApi)) {
@@ -98,7 +96,7 @@
 class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetBaseTest {
  public:
   virtual void SetUp() override {
-    hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>(CONTEXTHUB_SERVICE_NAME);
+    hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>();
     ASSERT_NE(hubApi, nullptr);
 
     // getHubs() must be called at least once for proper initialization of the
diff --git a/drm/1.0/IDrmPlugin.hal b/drm/1.0/IDrmPlugin.hal
index 5bae22d..083b311 100644
--- a/drm/1.0/IDrmPlugin.hal
+++ b/drm/1.0/IDrmPlugin.hal
@@ -179,8 +179,9 @@
      * certificate authority (CA) is an entity which issues digital certificates
      * for use by other parties. It is an example of a trusted third party.
      * @return status the status of the call. The status must be OK or one of
-     * the following errors: BAD_VALUE if the sessionId is invalid or
-     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision
+     * the following errors: BAD_VALUE if the sessionId is invalid,
+     * ERROR_DRM_CANNOT_HANDLE if the drm scheme does not require provisioning
+     * or ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision
      * request cannot be generated.
      * @return request if successful the opaque certificate request blob
      * is returned
diff --git a/drm/1.0/default/DrmFactory.cpp b/drm/1.0/default/DrmFactory.cpp
index 92f54f1..9ec0ab7 100644
--- a/drm/1.0/default/DrmFactory.cpp
+++ b/drm/1.0/default/DrmFactory.cpp
@@ -52,7 +52,7 @@
     }
 
     Return<void> DrmFactory::createPlugin(const hidl_array<uint8_t, 16>& uuid,
-            const hidl_string& appPackageName, createPlugin_cb _hidl_cb) {
+            const hidl_string& /* appPackageName */, createPlugin_cb _hidl_cb) {
 
         for (size_t i = 0; i < loader.factoryCount(); i++) {
             if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) {
diff --git a/evs/1.0/Android.bp b/evs/1.0/Android.bp
deleted file mode 100644
index 89bac10..0000000
--- a/evs/1.0/Android.bp
+++ /dev/null
@@ -1,83 +0,0 @@
-// This file is autogenerated by hidl-gen. Do not edit manually.
-
-filegroup {
-    name: "android.hardware.evs@1.0_hal",
-    srcs: [
-        "types.hal",
-        "IEvsCamera.hal",
-        "IEvsCameraStream.hal",
-        "IEvsDisplay.hal",
-        "IEvsEnumerator.hal",
-    ],
-}
-
-genrule {
-    name: "android.hardware.evs@1.0_genc++",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.evs@1.0",
-    srcs: [
-        ":android.hardware.evs@1.0_hal",
-    ],
-    out: [
-        "android/hardware/evs/1.0/types.cpp",
-        "android/hardware/evs/1.0/EvsCameraAll.cpp",
-        "android/hardware/evs/1.0/EvsCameraStreamAll.cpp",
-        "android/hardware/evs/1.0/EvsDisplayAll.cpp",
-        "android/hardware/evs/1.0/EvsEnumeratorAll.cpp",
-    ],
-}
-
-genrule {
-    name: "android.hardware.evs@1.0_genc++_headers",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.evs@1.0",
-    srcs: [
-        ":android.hardware.evs@1.0_hal",
-    ],
-    out: [
-        "android/hardware/evs/1.0/types.h",
-        "android/hardware/evs/1.0/IEvsCamera.h",
-        "android/hardware/evs/1.0/IHwEvsCamera.h",
-        "android/hardware/evs/1.0/BnHwEvsCamera.h",
-        "android/hardware/evs/1.0/BpHwEvsCamera.h",
-        "android/hardware/evs/1.0/BsEvsCamera.h",
-        "android/hardware/evs/1.0/IEvsCameraStream.h",
-        "android/hardware/evs/1.0/IHwEvsCameraStream.h",
-        "android/hardware/evs/1.0/BnHwEvsCameraStream.h",
-        "android/hardware/evs/1.0/BpHwEvsCameraStream.h",
-        "android/hardware/evs/1.0/BsEvsCameraStream.h",
-        "android/hardware/evs/1.0/IEvsDisplay.h",
-        "android/hardware/evs/1.0/IHwEvsDisplay.h",
-        "android/hardware/evs/1.0/BnHwEvsDisplay.h",
-        "android/hardware/evs/1.0/BpHwEvsDisplay.h",
-        "android/hardware/evs/1.0/BsEvsDisplay.h",
-        "android/hardware/evs/1.0/IEvsEnumerator.h",
-        "android/hardware/evs/1.0/IHwEvsEnumerator.h",
-        "android/hardware/evs/1.0/BnHwEvsEnumerator.h",
-        "android/hardware/evs/1.0/BpHwEvsEnumerator.h",
-        "android/hardware/evs/1.0/BsEvsEnumerator.h",
-    ],
-}
-
-cc_library_shared {
-    name: "android.hardware.evs@1.0",
-    generated_sources: ["android.hardware.evs@1.0_genc++"],
-    generated_headers: ["android.hardware.evs@1.0_genc++_headers"],
-    export_generated_headers: ["android.hardware.evs@1.0_genc++_headers"],
-    shared_libs: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "liblog",
-        "libutils",
-        "libcutils",
-        "android.hidl.base@1.0",
-    ],
-    export_shared_lib_headers: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "libutils",
-        "android.hidl.base@1.0",
-    ],
-}
diff --git a/evs/1.0/default/EvsCamera.h b/evs/1.0/default/EvsCamera.h
deleted file mode 100644
index 02a677c..0000000
--- a/evs/1.0/default/EvsCamera.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_EVS_V1_0_EVSCAMERA_H
-#define ANDROID_HARDWARE_EVS_V1_0_EVSCAMERA_H
-
-#include <android/hardware/evs/1.0/types.h>
-#include <android/hardware/evs/1.0/IEvsCamera.h>
-#include <ui/GraphicBuffer.h>
-
-#include <thread>
-
-
-namespace android {
-namespace hardware {
-namespace evs {
-namespace V1_0 {
-namespace implementation {
-
-
-class EvsCamera : public IEvsCamera {
-public:
-    // Methods from ::android::hardware::evs::V1_0::IEvsCamera follow.
-    Return<void> getId(getId_cb id_cb)  override;
-    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount)  override;
-    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream>& stream) override;
-    Return<void> doneWithFrame(const BufferDesc& buffer)  override;
-    Return<void> stopVideoStream()  override;
-    Return<int32_t> getExtendedInfo(uint32_t opaqueIdentifier)  override;
-    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue)  override;
-
-    // Implementation details
-    EvsCamera(const char* id);
-    virtual ~EvsCamera() override;
-
-    const CameraDesc& getDesc() { return mDescription; };
-
-    static const char kCameraName_Backup[];
-    static const char kCameraName_RightTurn[];
-
-private:
-    // These three functions are expected to be called while mAccessLock is held
-    bool     setAvailableFrames_Locked(unsigned bufferCount);
-    unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
-    unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
-
-    void generateFrames();
-    void fillTestFrame(const BufferDesc& buff);
-
-    CameraDesc                  mDescription = {};  // The properties of this camera
-
-    std::thread                 mCaptureThread;     // The thread we'll use to synthesize frames
-
-    uint32_t                    mWidth  = 0;        // Horizontal pixel count in the buffers
-    uint32_t                    mHeight = 0;        // Vertical pixel count in the buffers
-    uint32_t                    mFormat = 0;        // Values from android_pixel_format_t [TODO: YUV?  Leave opaque?]
-    uint32_t                    mUsage  = 0;        // Values from from Gralloc.h
-    uint32_t                    mStride = 0;        // Bytes per line in the buffers
-
-    sp<IEvsCameraStream>        mStream = nullptr;  // The callback used to deliver each frame
-
-    struct BufferRecord {
-        buffer_handle_t     handle;
-        bool                inUse;
-        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
-    };
-    std::vector<BufferRecord>   mBuffers;           // Graphics buffers to transfer images
-    unsigned                    mFramesAllowed;     // How many buffers are we currently using
-    unsigned                    mFramesInUse;       // How many buffers are currently outstanding
-
-    enum StreamStateValues {
-        STOPPED,
-        RUNNING,
-        STOPPING,
-    };
-    StreamStateValues           mStreamState;
-
-    // Syncrhonization necessary to deconflict mCaptureThread from the main service thread
-    std::mutex                  mAccessLock;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace hardware
-} // namespace android
-
-#endif  // ANDROID_HARDWARE_EVS_V1_0_EVSCAMERA_H
diff --git a/evs/1.0/default/android.hardware.evs@1.0-service.rc b/evs/1.0/default/android.hardware.evs@1.0-service.rc
deleted file mode 100644
index bb38668..0000000
--- a/evs/1.0/default/android.hardware.evs@1.0-service.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service evs-hal-1-0 /vendor/bin/hw/android.hardware.evs@1.0-service
-    class hal
-    user cameraserver
-    group camera
diff --git a/evs/Android.bp b/evs/Android.bp
deleted file mode 100644
index ba90f2c..0000000
--- a/evs/Android.bp
+++ /dev/null
@@ -1,5 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
-    "1.0",
-    "1.0/default",
-]
diff --git a/graphics/allocator/2.0/default/Gralloc.cpp b/graphics/allocator/2.0/default/Gralloc.cpp
index 3a102d1..0b9e863 100644
--- a/graphics/allocator/2.0/default/Gralloc.cpp
+++ b/graphics/allocator/2.0/default/Gralloc.cpp
@@ -131,7 +131,7 @@
 
 void GrallocHal::initCapabilities()
 {
-    uint32_t count;
+    uint32_t count = 0;
     mDevice->getCapabilities(mDevice, &count, nullptr);
 
     std::vector<Capability> caps(count);
diff --git a/graphics/allocator/2.0/vts/functional/Android.bp b/graphics/allocator/2.0/vts/functional/Android.bp
index fdc91ae..c3a16fb 100644
--- a/graphics/allocator/2.0/vts/functional/Android.bp
+++ b/graphics/allocator/2.0/vts/functional/Android.bp
@@ -14,6 +14,25 @@
 // limitations under the License.
 //
 
+cc_library_static {
+    name: "libVtsHalGraphicsAllocatorTestUtils",
+    srcs: ["VtsHalGraphicsAllocatorTestUtils.cpp"],
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetBaseTest",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-O0",
+        "-g",
+    ],
+    export_include_dirs: ["."],
+}
+
 cc_test {
     name: "VtsHalGraphicsAllocatorV2_0TargetTest",
     srcs: ["VtsHalGraphicsAllocatorV2_0TargetTest.cpp"],
@@ -27,8 +46,14 @@
         "libutils",
         "android.hardware.graphics.allocator@2.0",
     ],
-    static_libs: ["VtsHalHidlTargetBaseTest"],
+    static_libs: [
+        "libVtsHalGraphicsAllocatorTestUtils",
+        "VtsHalHidlTargetBaseTest",
+    ],
     cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
         "-O0",
         "-g",
     ]
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp
new file mode 100644
index 0000000..141743b
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetBaseTest.h>
+
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace tests {
+
+Allocator::Allocator() { init(); }
+
+void Allocator::init() {
+  mAllocator = ::testing::VtsHalHidlTargetBaseTest::getService<IAllocator>();
+  ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+  std::vector<IAllocator::Capability> capabilities = getCapabilities();
+  mCapabilities.insert(capabilities.begin(), capabilities.end());
+}
+
+sp<IAllocator> Allocator::getRaw() const { return mAllocator; }
+
+bool Allocator::hasCapability(IAllocator::Capability capability) const {
+  return mCapabilities.count(capability) > 0;
+}
+
+std::vector<IAllocator::Capability> Allocator::getCapabilities() {
+  std::vector<IAllocator::Capability> capabilities;
+  mAllocator->getCapabilities(
+      [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+
+  return capabilities;
+}
+
+std::string Allocator::dumpDebugInfo() {
+  std::string debugInfo;
+  mAllocator->dumpDebugInfo(
+      [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+  return debugInfo;
+}
+
+std::unique_ptr<AllocatorClient> Allocator::createClient() {
+  std::unique_ptr<AllocatorClient> client;
+  mAllocator->createClient([&](const auto& tmpError, const auto& tmpClient) {
+    ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+    client = std::make_unique<AllocatorClient>(tmpClient);
+  });
+
+  return client;
+}
+
+AllocatorClient::AllocatorClient(const sp<IAllocatorClient>& client)
+    : mClient(client) {}
+
+AllocatorClient::~AllocatorClient() {
+  for (auto buffer : mBuffers) {
+    EXPECT_EQ(Error::NONE, mClient->free(buffer))
+        << "failed to free buffer " << buffer;
+  }
+  mBuffers.clear();
+
+  for (auto descriptor : mDescriptors) {
+    EXPECT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor))
+        << "failed to destroy descriptor " << descriptor;
+  }
+  mDescriptors.clear();
+}
+
+sp<IAllocatorClient> AllocatorClient::getRaw() const { return mClient; }
+
+BufferDescriptor AllocatorClient::createDescriptor(
+    const IAllocatorClient::BufferDescriptorInfo& info) {
+  BufferDescriptor descriptor = 0;
+  mClient->createDescriptor(
+      info, [&](const auto& tmpError, const auto& tmpDescriptor) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+        descriptor = tmpDescriptor;
+
+        EXPECT_TRUE(mDescriptors.insert(descriptor).second)
+            << "duplicated descriptor id " << descriptor;
+      });
+
+  return descriptor;
+}
+
+void AllocatorClient::destroyDescriptor(BufferDescriptor descriptor) {
+  ASSERT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor))
+      << "failed to destroy descriptor " << descriptor;
+
+  mDescriptors.erase(descriptor);
+}
+
+Error AllocatorClient::testAllocate(
+    const std::vector<BufferDescriptor>& descriptors) {
+  return mClient->testAllocate(descriptors);
+}
+
+bool AllocatorClient::testAllocate(BufferDescriptor descriptor) {
+  std::vector<BufferDescriptor> descriptors(1, descriptor);
+  Error error = testAllocate(descriptors);
+  return (error == Error::NONE || error == Error::NOT_SHARED);
+}
+
+Error AllocatorClient::allocate(
+    const std::vector<BufferDescriptor>& descriptors,
+    std::vector<Buffer>& buffers) {
+  Error error = Error::NO_RESOURCES;
+  mClient->allocate(descriptors, [&](const auto& tmpError,
+                                     const auto& tmpBuffers) {
+    ASSERT_TRUE(tmpError == Error::NONE || tmpError == Error::NOT_SHARED)
+        << "failed to allocate buffer";
+    ASSERT_EQ(descriptors.size(), tmpBuffers.size()) << "invalid buffer count";
+
+    error = tmpError;
+    buffers = tmpBuffers;
+
+    for (auto buffer : buffers) {
+      EXPECT_TRUE(mBuffers.insert(buffer).second)
+          << "duplicated buffer id " << buffer;
+    }
+  });
+
+  return error;
+}
+
+Buffer AllocatorClient::allocate(BufferDescriptor descriptor) {
+  std::vector<BufferDescriptor> descriptors(1, descriptor);
+  std::vector<Buffer> buffers;
+  allocate(descriptors, buffers);
+  if (::testing::Test::HasFatalFailure()) {
+    return 0;
+  }
+
+  return buffers[0];
+}
+
+void AllocatorClient::free(Buffer buffer) {
+  ASSERT_EQ(Error::NONE, mClient->free(buffer))
+      << "failed to free buffer " << buffer;
+
+  mBuffers.erase(buffer);
+}
+
+native_handle_t* AllocatorClient::exportHandle(BufferDescriptor descriptor,
+                                               Buffer buffer) {
+  native_handle_t* handle;
+  mClient->exportHandle(
+      descriptor, buffer, [&](const auto& tmpError, const auto& tmpHandle) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to export buffer handle";
+        ASSERT_NE(nullptr, tmpHandle.getNativeHandle())
+            << "invalid buffer handle";
+
+        handle = native_handle_clone(tmpHandle.getNativeHandle());
+        ASSERT_NE(nullptr, handle) << "failed to clone handle";
+      });
+
+  return handle;
+}
+
+}  // namespace tests
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h
new file mode 100644
index 0000000..c9bfe8f
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
+#define VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace tests {
+
+class AllocatorClient;
+
+// A wrapper to IAllocator.
+class Allocator {
+ public:
+  Allocator();
+
+  sp<IAllocator> getRaw() const;
+
+  // Returns true when the allocator supports the specified capability.
+  bool hasCapability(IAllocator::Capability capability) const;
+
+  std::vector<IAllocator::Capability> getCapabilities();
+  std::string dumpDebugInfo();
+  std::unique_ptr<AllocatorClient> createClient();
+
+ private:
+  void init();
+
+  sp<IAllocator> mAllocator;
+  std::unordered_set<IAllocator::Capability> mCapabilities;
+};
+
+// A wrapper to IAllocatorClient.
+class AllocatorClient {
+ public:
+  AllocatorClient(const sp<IAllocatorClient>& client);
+  ~AllocatorClient();
+
+  sp<IAllocatorClient> getRaw() const;
+
+  BufferDescriptor createDescriptor(
+      const IAllocatorClient::BufferDescriptorInfo& info);
+  void destroyDescriptor(BufferDescriptor descriptor);
+
+  Error testAllocate(const std::vector<BufferDescriptor>& descriptors);
+  bool testAllocate(BufferDescriptor descriptor);
+
+  Error allocate(const std::vector<BufferDescriptor>& descriptors,
+                 std::vector<Buffer>& buffers);
+  Buffer allocate(BufferDescriptor descriptor);
+  void free(Buffer buffer);
+
+  // Returns a handle to the buffer.  The ownership of the handle is
+  // transferred to the caller.
+  native_handle_t* exportHandle(BufferDescriptor descriptor, Buffer buffer);
+
+ private:
+  sp<IAllocatorClient> mClient;
+
+  // Keep track of all descriptors and buffers.  When a test fails with
+  // ASSERT_*, the destructor will clean up the resources for the test.
+  std::unordered_set<BufferDescriptor> mDescriptors;
+  std::unordered_set<Buffer> mBuffers;
+};
+
+}  // namespace tests
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp
index a8ced8c..2e3ed73 100644
--- a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp
+++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp
@@ -16,12 +16,11 @@
 
 #define LOG_TAG "graphics_allocator_hidl_hal_test"
 
-#include <unordered_set>
-
 #include <android-base/logging.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <VtsHalHidlTargetBaseTest.h>
 
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -34,55 +33,18 @@
 
 #define CHECK_FEATURE_OR_SKIP(FEATURE_NAME)                 \
   do {                                                      \
-    if (!hasCapability(FEATURE_NAME)) {                     \
+    if (!mAllocator->hasCapability(FEATURE_NAME)) {         \
       std::cout << "[  SKIPPED ] Feature " << #FEATURE_NAME \
                 << " not supported" << std::endl;           \
       return;                                               \
     }                                                       \
   } while (0)
 
-class TempDescriptor {
- public:
-  TempDescriptor(const sp<IAllocatorClient>& client,
-                 const IAllocatorClient::BufferDescriptorInfo& info)
-      : mClient(client), mError(Error::NO_RESOURCES) {
-    mClient->createDescriptor(
-        info, [&](const auto& tmpError, const auto& tmpDescriptor) {
-          mError = tmpError;
-          mDescriptor = tmpDescriptor;
-        });
-  }
-
-  ~TempDescriptor() {
-    if (mError == Error::NONE) {
-      mClient->destroyDescriptor(mDescriptor);
-    }
-  }
-
-  bool isValid() const { return (mError == Error::NONE); }
-
-  operator BufferDescriptor() const { return mDescriptor; }
-
- private:
-  sp<IAllocatorClient> mClient;
-  Error mError;
-  BufferDescriptor mDescriptor;
-};
-
 class GraphicsAllocatorHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
  protected:
   void SetUp() override {
-    mAllocator = ::testing::VtsHalHidlTargetBaseTest::getService<IAllocator>();
-    ASSERT_NE(mAllocator, nullptr);
-
-    mAllocator->createClient([this](const auto& error, const auto& client) {
-      if (error == Error::NONE) {
-        mClient = client;
-      }
-    });
-    ASSERT_NE(mClient, nullptr);
-
-    initCapabilities();
+    ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
+    ASSERT_NO_FATAL_FAILURE(mClient = mAllocator->createClient());
 
     mDummyDescriptorInfo.width = 64;
     mDummyDescriptorInfo.height = 64;
@@ -96,66 +58,27 @@
 
   void TearDown() override {}
 
-  /**
-   * Initialize the set of supported capabilities.
-   */
-  void initCapabilities() {
-    mAllocator->getCapabilities([this](const auto& capabilities) {
-      std::vector<IAllocator::Capability> caps = capabilities;
-      mCapabilities.insert(caps.cbegin(), caps.cend());
-    });
-  }
-
-  /**
-   * Test whether a capability is supported.
-   */
-  bool hasCapability(IAllocator::Capability capability) const {
-    return (mCapabilities.count(capability) > 0);
-  }
-
-  sp<IAllocator> mAllocator;
-  sp<IAllocatorClient> mClient;
+  std::unique_ptr<Allocator> mAllocator;
+  std::unique_ptr<AllocatorClient> mClient;
   IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
-
- private:
-  std::unordered_set<IAllocator::Capability> mCapabilities;
 };
 
 TEST_F(GraphicsAllocatorHidlTest, GetCapabilities) {
-  auto ret = mAllocator->getCapabilities([](const auto& capabilities) {
-    std::vector<IAllocator::Capability> caps = capabilities;
-    for (auto cap : caps) {
-      EXPECT_NE(IAllocator::Capability::INVALID, cap);
-    }
-  });
-
-  ASSERT_TRUE(ret.isOk());
+  auto capabilities = mAllocator->getCapabilities();
+  for (auto cap : capabilities) {
+    EXPECT_NE(IAllocator::Capability::INVALID, cap);
+  }
 }
 
 TEST_F(GraphicsAllocatorHidlTest, DumpDebugInfo) {
-  auto ret = mAllocator->dumpDebugInfo([](const auto&) {
-    // nothing to do
-  });
-
-  ASSERT_TRUE(ret.isOk());
+  mAllocator->dumpDebugInfo();
 }
 
 TEST_F(GraphicsAllocatorHidlTest, CreateDestroyDescriptor) {
-  Error error;
   BufferDescriptor descriptor;
-  auto ret = mClient->createDescriptor(
-      mDummyDescriptorInfo,
-      [&](const auto& tmpError, const auto& tmpDescriptor) {
-        error = tmpError;
-        descriptor = tmpDescriptor;
-      });
-
-  ASSERT_TRUE(ret.isOk());
-  ASSERT_EQ(Error::NONE, error);
-
-  auto err_ret = mClient->destroyDescriptor(descriptor);
-  ASSERT_TRUE(err_ret.isOk());
-  ASSERT_EQ(Error::NONE, static_cast<Error>(err_ret));
+  ASSERT_NO_FATAL_FAILURE(descriptor =
+                              mClient->createDescriptor(mDummyDescriptorInfo));
+  mClient->destroyDescriptor(descriptor);
 }
 
 /**
@@ -164,18 +87,11 @@
 TEST_F(GraphicsAllocatorHidlTest, TestAllocateBasic) {
   CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
 
-  TempDescriptor descriptor(mClient, mDummyDescriptorInfo);
-  ASSERT_TRUE(descriptor.isValid());
+  BufferDescriptor descriptor;
+  ASSERT_NO_FATAL_FAILURE(descriptor =
+                              mClient->createDescriptor(mDummyDescriptorInfo));
 
-  hidl_vec<BufferDescriptor> descriptors;
-  descriptors.resize(1);
-  descriptors[0] = descriptor;
-
-  auto ret = mClient->testAllocate(descriptors);
-  ASSERT_TRUE(ret.isOk());
-
-  auto error = static_cast<Error>(ret);
-  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
+  ASSERT_TRUE(mClient->testAllocate(descriptor));
 }
 
 /**
@@ -184,18 +100,16 @@
 TEST_F(GraphicsAllocatorHidlTest, TestAllocateArray) {
   CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
 
-  TempDescriptor descriptor(mClient, mDummyDescriptorInfo);
-  ASSERT_TRUE(descriptor.isValid());
+  BufferDescriptor descriptor;
+  ASSERT_NO_FATAL_FAILURE(descriptor =
+                              mClient->createDescriptor(mDummyDescriptorInfo));
 
   hidl_vec<BufferDescriptor> descriptors;
   descriptors.resize(2);
   descriptors[0] = descriptor;
   descriptors[1] = descriptor;
 
-  auto ret = mClient->testAllocate(descriptors);
-  ASSERT_TRUE(ret.isOk());
-
-  auto error = static_cast<Error>(ret);
+  auto error = mClient->testAllocate(descriptors);
   ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
 }
 
@@ -203,41 +117,27 @@
  * Test allocate/free with a single buffer descriptor.
  */
 TEST_F(GraphicsAllocatorHidlTest, AllocateFreeBasic) {
-  TempDescriptor descriptor(mClient, mDummyDescriptorInfo);
-  ASSERT_TRUE(descriptor.isValid());
+  BufferDescriptor descriptor;
+  ASSERT_NO_FATAL_FAILURE(descriptor =
+                              mClient->createDescriptor(mDummyDescriptorInfo));
 
-  hidl_vec<BufferDescriptor> descriptors;
-  descriptors.resize(1);
-  descriptors[0] = descriptor;
+  Buffer buffer;
+  ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor));
 
-  Error error;
-  std::vector<Buffer> buffers;
-  auto ret = mClient->allocate(
-      descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
-        error = tmpError;
-        buffers = tmpBuffers;
-      });
-
-  ASSERT_TRUE(ret.isOk());
-  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
-  EXPECT_EQ(1u, buffers.size());
-
-  if (!buffers.empty()) {
-    auto err_ret = mClient->free(buffers[0]);
-    EXPECT_TRUE(err_ret.isOk());
-    EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
-  }
+  mClient->free(buffer);
 }
 
 /**
  * Test allocate/free with an array of buffer descriptors.
  */
 TEST_F(GraphicsAllocatorHidlTest, AllocateFreeArray) {
-  TempDescriptor descriptor1(mClient, mDummyDescriptorInfo);
-  ASSERT_TRUE(descriptor1.isValid());
+  BufferDescriptor descriptor1;
+  ASSERT_NO_FATAL_FAILURE(descriptor1 =
+                              mClient->createDescriptor(mDummyDescriptorInfo));
 
-  TempDescriptor descriptor2(mClient, mDummyDescriptorInfo);
-  ASSERT_TRUE(descriptor2.isValid());
+  BufferDescriptor descriptor2;
+  ASSERT_NO_FATAL_FAILURE(descriptor2 =
+                              mClient->createDescriptor(mDummyDescriptorInfo));
 
   hidl_vec<BufferDescriptor> descriptors;
   descriptors.resize(3);
@@ -245,54 +145,27 @@
   descriptors[1] = descriptor1;
   descriptors[2] = descriptor2;
 
-  Error error;
   std::vector<Buffer> buffers;
-  auto ret = mClient->allocate(
-      descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
-        error = tmpError;
-        buffers = tmpBuffers;
-      });
-
-  ASSERT_TRUE(ret.isOk());
-  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
-  EXPECT_EQ(descriptors.size(), buffers.size());
+  ASSERT_NO_FATAL_FAILURE(mClient->allocate(descriptors, buffers));
 
   for (auto buf : buffers) {
-    auto err_ret = mClient->free(buf);
-    EXPECT_TRUE(err_ret.isOk());
-    EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
+    mClient->free(buf);
   }
 }
 
 TEST_F(GraphicsAllocatorHidlTest, ExportHandle) {
-  TempDescriptor descriptor(mClient, mDummyDescriptorInfo);
-  ASSERT_TRUE(descriptor.isValid());
+  BufferDescriptor descriptor;
+  ASSERT_NO_FATAL_FAILURE(descriptor =
+                              mClient->createDescriptor(mDummyDescriptorInfo));
 
-  hidl_vec<BufferDescriptor> descriptors;
-  descriptors.resize(1);
-  descriptors[0] = descriptor;
+  Buffer buffer;
+  ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor));
 
-  Error error;
-  std::vector<Buffer> buffers;
-  auto ret = mClient->allocate(
-      descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
-        error = tmpError;
-        buffers = tmpBuffers;
-      });
+  native_handle_t* handle;
+  ASSERT_NO_FATAL_FAILURE(handle = mClient->exportHandle(descriptor, buffer));
 
-  ASSERT_TRUE(ret.isOk());
-  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
-  ASSERT_EQ(1u, buffers.size());
-
-  ret = mClient->exportHandle(
-      descriptors[0], buffers[0],
-      [&](const auto& tmpError, const auto&) { error = tmpError; });
-  EXPECT_TRUE(ret.isOk());
-  EXPECT_EQ(Error::NONE, error);
-
-  auto err_ret = mClient->free(buffers[0]);
-  EXPECT_TRUE(err_ret.isOk());
-  EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
+  native_handle_close(handle);
+  native_handle_delete(handle);
 }
 
 }  // namespace anonymous
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 9be04d1..825bf07 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -14,6 +14,23 @@
 // limitations under the License.
 //
 
+cc_library_static {
+    name: "libVtsHalGraphicsComposerTestUtils",
+    srcs: ["VtsHalGraphicsComposerTestUtils.cpp"],
+    shared_libs: ["android.hardware.graphics.composer@2.1"],
+    static_libs: [
+        "VtsHalHidlTargetBaseTest",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-O0",
+        "-g",
+    ],
+    export_include_dirs: ["."],
+}
+
 cc_test {
     name: "VtsHalGraphicsComposerV2_1TargetTest",
     srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
@@ -31,8 +48,17 @@
         "libsync",
         "libutils",
     ],
-    static_libs: ["VtsHalHidlTargetBaseTest", "libhwcomposer-command-buffer"],
+    static_libs: [
+        "libhwcomposer-command-buffer",
+        "libVtsHalGraphicsAllocatorTestUtils",
+        "libVtsHalGraphicsComposerTestUtils",
+        "libVtsHalGraphicsMapperTestUtils",
+        "VtsHalHidlTargetBaseTest",
+    ],
     cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
         "-O0",
         "-g",
     ]
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
new file mode 100644
index 0000000..5b6a108
--- /dev/null
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetBaseTest.h>
+
+#include "VtsHalGraphicsComposerTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace tests {
+
+Composer::Composer() { init(); }
+
+void Composer::init() {
+  mComposer = ::testing::VtsHalHidlTargetBaseTest::getService<IComposer>();
+  ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
+
+  std::vector<IComposer::Capability> capabilities = getCapabilities();
+  mCapabilities.insert(capabilities.begin(), capabilities.end());
+}
+
+sp<IComposer> Composer::getRaw() const { return mComposer; }
+
+bool Composer::hasCapability(IComposer::Capability capability) const {
+  return mCapabilities.count(capability) > 0;
+}
+
+std::vector<IComposer::Capability> Composer::getCapabilities() {
+  std::vector<IComposer::Capability> capabilities;
+  mComposer->getCapabilities(
+      [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+
+  return capabilities;
+}
+
+std::string Composer::dumpDebugInfo() {
+  std::string debugInfo;
+  mComposer->dumpDebugInfo(
+      [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+  return debugInfo;
+}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+  std::unique_ptr<ComposerClient> client;
+  mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+    ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+    client = std::make_unique<ComposerClient>(tmpClient);
+  });
+
+  return client;
+}
+
+ComposerClient::ComposerClient(const sp<IComposerClient>& client)
+    : mClient(client) {}
+
+ComposerClient::~ComposerClient() {
+  for (auto it : mDisplayResources) {
+    Display display = it.first;
+    DisplayResource& resource = it.second;
+
+    for (auto layer : resource.layers) {
+      EXPECT_EQ(Error::NONE, mClient->destroyLayer(display, layer))
+          << "failed to destroy layer " << layer;
+    }
+
+    if (resource.isVirtual) {
+      EXPECT_EQ(Error::NONE, mClient->destroyVirtualDisplay(display))
+          << "failed to destroy virtual display " << display;
+    }
+  }
+  mDisplayResources.clear();
+}
+
+sp<IComposerClient> ComposerClient::getRaw() const { return mClient; }
+
+void ComposerClient::registerCallback(const sp<IComposerCallback>& callback) {
+  mClient->registerCallback(callback);
+}
+
+uint32_t ComposerClient::getMaxVirtualDisplayCount() {
+  return mClient->getMaxVirtualDisplayCount();
+}
+
+Display ComposerClient::createVirtualDisplay(uint32_t width, uint32_t height,
+                                             PixelFormat formatHint,
+                                             uint32_t outputBufferSlotCount,
+                                             PixelFormat* outFormat) {
+  Display display = 0;
+  mClient->createVirtualDisplay(
+      width, height, formatHint, outputBufferSlotCount,
+      [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display";
+        display = tmpDisplay;
+        *outFormat = tmpFormat;
+
+        ASSERT_TRUE(
+            mDisplayResources.insert({display, DisplayResource(true)}).second)
+            << "duplicated virtual display id " << display;
+      });
+
+  return display;
+}
+
+void ComposerClient::destroyVirtualDisplay(Display display) {
+  Error error = mClient->destroyVirtualDisplay(display);
+  ASSERT_EQ(Error::NONE, error)
+      << "failed to destroy virtual display " << display;
+
+  mDisplayResources.erase(display);
+}
+
+Layer ComposerClient::createLayer(Display display, uint32_t bufferSlotCount) {
+  Layer layer = 0;
+  mClient->createLayer(
+      display, bufferSlotCount,
+      [&](const auto& tmpError, const auto& tmpLayer) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create layer";
+        layer = tmpLayer;
+
+        auto resourceIt = mDisplayResources.find(display);
+        if (resourceIt == mDisplayResources.end()) {
+          resourceIt =
+              mDisplayResources.insert({display, DisplayResource(false)}).first;
+        }
+
+        ASSERT_TRUE(resourceIt->second.layers.insert(layer).second)
+            << "duplicated layer id " << layer;
+      });
+
+  return layer;
+}
+
+void ComposerClient::destroyLayer(Display display, Layer layer) {
+  Error error = mClient->destroyLayer(display, layer);
+  ASSERT_EQ(Error::NONE, error) << "failed to destroy layer " << layer;
+
+  auto resourceIt = mDisplayResources.find(display);
+  ASSERT_NE(mDisplayResources.end(), resourceIt);
+  resourceIt->second.layers.erase(layer);
+}
+
+Config ComposerClient::getActiveConfig(Display display) {
+  Config config = 0;
+  mClient->getActiveConfig(
+      display, [&](const auto& tmpError, const auto& tmpConfig) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get active config";
+        config = tmpConfig;
+      });
+
+  return config;
+}
+
+bool ComposerClient::getClientTargetSupport(Display display, uint32_t width,
+                                            uint32_t height, PixelFormat format,
+                                            Dataspace dataspace) {
+  Error error = mClient->getClientTargetSupport(display, width, height, format,
+                                                dataspace);
+  return error == Error::NONE;
+}
+
+std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
+  std::vector<ColorMode> modes;
+  mClient->getColorModes(
+      display, [&](const auto& tmpError, const auto& tmpMode) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get color mode";
+        modes = tmpMode;
+      });
+
+  return modes;
+}
+
+int32_t ComposerClient::getDisplayAttribute(
+    Display display, Config config, IComposerClient::Attribute attribute) {
+  int32_t value = 0;
+  mClient->getDisplayAttribute(display, config, attribute,
+                               [&](const auto& tmpError, const auto& tmpValue) {
+                                 ASSERT_EQ(Error::NONE, tmpError)
+                                     << "failed to get display attribute";
+                                 value = tmpValue;
+                               });
+
+  return value;
+}
+
+std::vector<Config> ComposerClient::getDisplayConfigs(Display display) {
+  std::vector<Config> configs;
+  mClient->getDisplayConfigs(
+      display, [&](const auto& tmpError, const auto& tmpConfigs) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get display configs";
+        configs = tmpConfigs;
+      });
+
+  return configs;
+}
+
+std::string ComposerClient::getDisplayName(Display display) {
+  std::string name;
+  mClient->getDisplayName(
+      display, [&](const auto& tmpError, const auto& tmpName) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get display name";
+        name = tmpName.c_str();
+      });
+
+  return name;
+}
+
+IComposerClient::DisplayType ComposerClient::getDisplayType(Display display) {
+  IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
+  mClient->getDisplayType(
+      display, [&](const auto& tmpError, const auto& tmpType) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get display type";
+        type = tmpType;
+      });
+
+  return type;
+}
+
+bool ComposerClient::getDozeSupport(Display display) {
+  bool support = false;
+  mClient->getDozeSupport(
+      display, [&](const auto& tmpError, const auto& tmpSupport) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get doze support";
+        support = tmpSupport;
+      });
+
+  return support;
+}
+
+std::vector<Hdr> ComposerClient::getHdrCapabilities(
+    Display display, float* outMaxLuminance, float* outMaxAverageLuminance,
+    float* outMinLuminance) {
+  std::vector<Hdr> types;
+  mClient->getHdrCapabilities(
+      display,
+      [&](const auto& tmpError, const auto& tmpTypes,
+          const auto& tmpMaxLuminance, const auto& tmpMaxAverageLuminance,
+          const auto& tmpMinLuminance) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities";
+        types = tmpTypes;
+        *outMaxLuminance = tmpMaxLuminance;
+        *outMaxAverageLuminance = tmpMaxAverageLuminance;
+        *outMinLuminance = tmpMinLuminance;
+      });
+
+  return types;
+}
+
+void ComposerClient::setClientTargetSlotCount(Display display,
+                                              uint32_t clientTargetSlotCount) {
+  Error error =
+      mClient->setClientTargetSlotCount(display, clientTargetSlotCount);
+  ASSERT_EQ(Error::NONE, error) << "failed to set client target slot count";
+}
+
+void ComposerClient::setActiveConfig(Display display, Config config) {
+  Error error = mClient->setActiveConfig(display, config);
+  ASSERT_EQ(Error::NONE, error) << "failed to set active config";
+}
+
+void ComposerClient::setColorMode(Display display, ColorMode mode) {
+  Error error = mClient->setColorMode(display, mode);
+  ASSERT_EQ(Error::NONE, error) << "failed to set color mode";
+}
+
+void ComposerClient::setPowerMode(Display display,
+                                  IComposerClient::PowerMode mode) {
+  Error error = mClient->setPowerMode(display, mode);
+  ASSERT_EQ(Error::NONE, error) << "failed to set power mode";
+}
+
+void ComposerClient::setVsyncEnabled(Display display, bool enabled) {
+  IComposerClient::Vsync vsync = (enabled) ? IComposerClient::Vsync::ENABLE
+                                           : IComposerClient::Vsync::DISABLE;
+  Error error = mClient->setVsyncEnabled(display, vsync);
+  ASSERT_EQ(Error::NONE, error) << "failed to set vsync mode";
+}
+
+}  // namespace tests
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
new file mode 100644
index 0000000..4b57264
--- /dev/null
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VTS_HAL_GRAPHICS_COMPOSER_UTILS
+#define VTS_HAL_GRAPHICS_COMPOSER_UTILS
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace tests {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer {
+ public:
+  Composer();
+
+  sp<IComposer> getRaw() const;
+
+  // Returns true when the composer supports the specified capability.
+  bool hasCapability(IComposer::Capability capability) const;
+
+  std::vector<IComposer::Capability> getCapabilities();
+  std::string dumpDebugInfo();
+  std::unique_ptr<ComposerClient> createClient();
+
+ private:
+  void init();
+
+  sp<IComposer> mComposer;
+  std::unordered_set<IComposer::Capability> mCapabilities;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient {
+ public:
+  ComposerClient(const sp<IComposerClient>& client);
+  ~ComposerClient();
+
+  sp<IComposerClient> getRaw() const;
+
+  void registerCallback(const sp<IComposerCallback>& callback);
+  uint32_t getMaxVirtualDisplayCount();
+
+  Display createVirtualDisplay(uint32_t width, uint32_t height,
+                               PixelFormat formatHint,
+                               uint32_t outputBufferSlotCount,
+                               PixelFormat* outFormat);
+  void destroyVirtualDisplay(Display display);
+
+  Layer createLayer(Display display, uint32_t bufferSlotCount);
+  void destroyLayer(Display display, Layer layer);
+
+  Config getActiveConfig(Display display);
+  bool getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+                              PixelFormat format, Dataspace dataspace);
+  std::vector<ColorMode> getColorModes(Display display);
+  int32_t getDisplayAttribute(Display display, Config config,
+                              IComposerClient::Attribute attribute);
+  std::vector<Config> getDisplayConfigs(Display display);
+  std::string getDisplayName(Display display);
+  IComposerClient::DisplayType getDisplayType(Display display);
+  bool getDozeSupport(Display display);
+  std::vector<Hdr> getHdrCapabilities(Display display, float* outMaxLuminance,
+                                      float* outMaxAverageLuminance,
+                                      float* outMinLuminance);
+
+  void setClientTargetSlotCount(Display display,
+                                uint32_t clientTargetSlotCount);
+  void setActiveConfig(Display display, Config config);
+  void setColorMode(Display display, ColorMode mode);
+  void setPowerMode(Display display, IComposerClient::PowerMode mode);
+  void setVsyncEnabled(Display display, bool enabled);
+
+ private:
+  sp<IComposerClient> mClient;
+
+  // Keep track of all virtual displays and layers.  When a test fails with
+  // ASSERT_*, the destructor will clean up the resources for the test.
+  struct DisplayResource {
+    DisplayResource(bool isVirtual_) : isVirtual(isVirtual_) {}
+
+    bool isVirtual;
+    std::unordered_set<Layer> layers;
+  };
+  std::unordered_map<Display, DisplayResource> mDisplayResources;
+};
+
+}  // namespace tests
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // VTS_HAL_GRAPHICS_COMPOSER_UTILS
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index a565845..0390c88 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -18,9 +18,9 @@
 
 #include <IComposerCommandBuffer.h>
 #include <android-base/logging.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+#include "VtsHalGraphicsComposerTestUtils.h"
+#include "VtsHalGraphicsMapperTestUtils.h"
 
 #include <VtsHalHidlTargetBaseTest.h>
 #include <unistd.h>
@@ -46,12 +46,15 @@
 using android::hardware::graphics::allocator::V2_0::IAllocator;
 using android::hardware::graphics::allocator::V2_0::IAllocatorClient;
 using android::hardware::graphics::allocator::V2_0::ProducerUsage;
+using android::hardware::graphics::allocator::V2_0::tests::Allocator;
+using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient;
 using android::hardware::graphics::common::V1_0::ColorMode;
 using android::hardware::graphics::common::V1_0::ColorTransform;
 using android::hardware::graphics::common::V1_0::Dataspace;
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
 using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::tests::Mapper;
 using GrallocError = android::hardware::graphics::allocator::V2_0::Error;
 
 // IComposerCallback to be installed with IComposerClient::registerCallback.
@@ -134,13 +137,8 @@
 class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
  protected:
   void SetUp() override {
-    mComposer = ::testing::VtsHalHidlTargetBaseTest::getService<IComposer>();
-    ASSERT_NE(nullptr, mComposer.get());
-
-    mComposerClient = createClient();
-    ASSERT_NE(nullptr, mComposerClient.get());
-
-    initCapabilities();
+    ASSERT_NO_FATAL_FAILURE(mComposer = std::make_unique<Composer>());
+    ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
 
     mComposerCallback = new GraphicsComposerCallback;
     mComposerClient->registerCallback(mComposerCallback);
@@ -157,177 +155,16 @@
     }
   }
 
-  /**
-   * Initialize the set of supported capabilities.
-   */
-  void initCapabilities() {
-    mComposer->getCapabilities([this](const auto& capabilities) {
-      std::vector<IComposer::Capability> caps = capabilities;
-      mCapabilities.insert(caps.cbegin(), caps.cend());
-    });
-  }
-
-  /**
-   * Test whether a capability is supported.
-   */
-  bool hasCapability(IComposer::Capability capability) const {
-    return (mCapabilities.count(capability) > 0);
-  }
-
-  IComposerClient::DisplayType getDisplayType(Display display) {
-    IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
-    mComposerClient->getDisplayType(
-        display, [&](const auto& tmpError, const auto& tmpType) {
-          ASSERT_EQ(Error::NONE, tmpError);
-          type = tmpType;
-        });
-    return type;
-  }
-
-  Error createVirtualDisplay(Display* outDisplay) {
-    auto ret_count = mComposerClient->getMaxVirtualDisplayCount();
-    if (ret_count == 0) {
-      return Error::UNSUPPORTED;
-    }
-
-    Error err = Error::NO_RESOURCES;
-    Display display;
-    mComposerClient->createVirtualDisplay(
-        64, 64, PixelFormat::IMPLEMENTATION_DEFINED, kBufferSlotCount,
-        [&](const auto& tmpError, const auto& tmpDisplay, const auto&) {
-          err = tmpError;
-          display = tmpDisplay;
-        });
-
-    *outDisplay = display;
-    return err;
-  }
-
-  void destroyVirtualDisplay(Display display) {
-    auto ret = mComposerClient->destroyVirtualDisplay(display);
-    ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-  }
-
-  Error createLayer(Layer* outLayer) {
-    Error err = Error::NO_RESOURCES;
-    Layer layer;
-    mComposerClient->createLayer(
-        mPrimaryDisplay, kBufferSlotCount,
-        [&](const auto& tmpError, const auto& tmpLayer) {
-          err = tmpError;
-          layer = tmpLayer;
-        });
-
-    *outLayer = layer;
-    return err;
-  }
-
-  void destroyLayer(Layer layer) {
-    auto ret = mComposerClient->destroyLayer(mPrimaryDisplay, layer);
-    ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-  }
-
-  int32_t getDisplayAttribute(Config config,
-                              IComposerClient::Attribute attribute) {
-    int32_t value = -1;
-    mComposerClient->getDisplayAttribute(
-        mPrimaryDisplay, config, attribute,
-        [&](const auto& tmpError, const auto& tmpValue) {
-          ASSERT_EQ(Error::NONE, tmpError);
-          value = tmpValue;
-        });
-    return value;
-  }
-
-  std::vector<Config> getDisplayConfigs() {
-    std::vector<Config> configs;
-    mComposerClient->getDisplayConfigs(
-        mPrimaryDisplay, [&](const auto& tmpError, const auto& tmpConfigs) {
-          ASSERT_EQ(Error::NONE, tmpError);
-
-          configs = tmpConfigs;
-          ASSERT_FALSE(configs.empty());
-        });
-
-    return configs;
-  }
-
-  std::vector<ColorMode> getColorModes() {
-    std::vector<ColorMode> modes;
-    mComposerClient->getColorModes(
-        mPrimaryDisplay, [&](const auto& tmpError, const auto& tmpModes) {
-          ASSERT_EQ(Error::NONE, tmpError);
-
-          modes = tmpModes;
-          ASSERT_NE(modes.end(),
-                    std::find(modes.begin(), modes.end(), ColorMode::NATIVE));
-        });
-
-    return modes;
-  }
-
-  std::vector<IComposerClient::PowerMode> getPowerModes() {
-    std::vector<IComposerClient::PowerMode> modes;
-    modes.push_back(IComposerClient::PowerMode::OFF);
-
-    mComposerClient->getDozeSupport(
-        mPrimaryDisplay, [&](const auto& tmpError, const auto& tmpSupport) {
-          ASSERT_EQ(Error::NONE, tmpError);
-          if (tmpSupport) {
-            modes.push_back(IComposerClient::PowerMode::DOZE);
-            modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
-          }
-        });
-
-    // push ON last
-    modes.push_back(IComposerClient::PowerMode::ON);
-
-    return modes;
-  }
-
-  void setActiveConfig(Config config) {
-    auto ret = mComposerClient->setActiveConfig(mPrimaryDisplay, config);
-    ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-  }
-
-  void setColorMode(ColorMode mode) {
-    auto ret = mComposerClient->setColorMode(mPrimaryDisplay, mode);
-    ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-  }
-
-  void setPowerMode(IComposerClient::PowerMode mode) {
-    auto ret = mComposerClient->setPowerMode(mPrimaryDisplay, mode);
-    ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-  }
-
-  void setVsyncEnabled(bool enable) {
-    auto ret = mComposerClient->setVsyncEnabled(
-        mPrimaryDisplay,
-        enable ? IComposerClient::Vsync::ENABLE
-               : IComposerClient::Vsync::DISABLE);
-    ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-  }
   // use the slot count usually set by SF
   static constexpr uint32_t kBufferSlotCount = 64;
 
-  sp<IComposer> mComposer;
-  sp<IComposerClient> mComposerClient;
+  std::unique_ptr<Composer> mComposer;
+  std::unique_ptr<ComposerClient> mComposerClient;
   sp<GraphicsComposerCallback> mComposerCallback;
   // the first display and is assumed never to be removed
   Display mPrimaryDisplay;
 
  private:
-  sp<IComposerClient> createClient() {
-    sp<IComposerClient> client;
-    mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
-      if (tmpError == Error::NONE) {
-        client = tmpClient;
-      }
-    });
-
-    return client;
-  }
-
   Display waitForFirstDisplay() {
     while (true) {
       std::vector<Display> displays = mComposerCallback->getDisplays();
@@ -339,9 +176,6 @@
       return displays[0];
     }
   }
-
-  // the set of all supported capabilities
-  std::unordered_set<IComposer::Capability> mCapabilities;
 };
 
 /**
@@ -350,22 +184,16 @@
  * Test that IComposer::getCapabilities returns no invalid capabilities.
  */
 TEST_F(GraphicsComposerHidlTest, GetCapabilities) {
-  mComposer->getCapabilities([](const auto& tmpCapabilities) {
-    std::vector<IComposer::Capability> capabilities = tmpCapabilities;
-    ASSERT_EQ(capabilities.end(),
-              std::find(capabilities.begin(), capabilities.end(),
-                        IComposer::Capability::INVALID));
-  });
+  auto capabilities = mComposer->getCapabilities();
+  ASSERT_EQ(capabilities.end(),
+            std::find(capabilities.begin(), capabilities.end(),
+                      IComposer::Capability::INVALID));
 }
 
 /**
  * Test IComposer::dumpDebugInfo.
  */
-TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) {
-  mComposer->dumpDebugInfo([](const auto&) {
-    // nothing to do
-  });
-}
+TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) { mComposer->dumpDebugInfo(); }
 
 /**
  * Test IComposer::createClient.
@@ -373,7 +201,7 @@
  * Test that IComposerClient is a singleton.
  */
 TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) {
-  mComposer->createClient([&](const auto& tmpError, const auto&) {
+  mComposer->getRaw()->createClient([&](const auto& tmpError, const auto&) {
     EXPECT_EQ(Error::NO_RESOURCES, tmpError);
   });
 }
@@ -385,19 +213,22 @@
  * Test that virtual displays can be created and has the correct display type.
  */
 TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) {
-  Display display;
-  Error err = createVirtualDisplay(&display);
-  if (err == Error::UNSUPPORTED) {
+  if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
     GTEST_SUCCEED() << "no virtual display support";
     return;
   }
-  ASSERT_EQ(Error::NONE, err);
+
+  Display display;
+  PixelFormat format;
+  ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay(
+                              64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
+                              kBufferSlotCount, &format));
 
   // test display type
-  IComposerClient::DisplayType type = getDisplayType(display);
+  IComposerClient::DisplayType type = mComposerClient->getDisplayType(display);
   EXPECT_EQ(IComposerClient::DisplayType::VIRTUAL, type);
 
-  destroyVirtualDisplay(display);
+  mComposerClient->destroyVirtualDisplay(display);
 }
 
 /**
@@ -407,20 +238,17 @@
  */
 TEST_F(GraphicsComposerHidlTest, CreateLayer) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
-  destroyLayer(layer);
+  mComposerClient->destroyLayer(mPrimaryDisplay, layer);
 }
 
 /**
  * Test IComposerClient::getDisplayName.
  */
 TEST_F(GraphicsComposerHidlTest, GetDisplayName) {
-  mComposerClient->getDisplayName(mPrimaryDisplay,
-                                  [&](const auto& tmpError, const auto&) {
-                                    ASSERT_EQ(Error::NONE, tmpError);
-                                  });
+  mComposerClient->getDisplayName(mPrimaryDisplay);
 }
 
 /**
@@ -430,8 +258,8 @@
  * for the primary display.
  */
 TEST_F(GraphicsComposerHidlTest, GetDisplayType) {
-  IComposerClient::DisplayType type = getDisplayType(mPrimaryDisplay);
-  EXPECT_EQ(IComposerClient::DisplayType::PHYSICAL, type);
+  ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL,
+            mComposerClient->getDisplayType(mPrimaryDisplay));
 }
 
 /**
@@ -441,21 +269,21 @@
  * required client targets.
  */
 TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) {
-  std::vector<Config> configs = getDisplayConfigs();
+  std::vector<Config> configs =
+      mComposerClient->getDisplayConfigs(mPrimaryDisplay);
   for (auto config : configs) {
-    int32_t width =
-        getDisplayAttribute(config, IComposerClient::Attribute::WIDTH);
-    int32_t height =
-        getDisplayAttribute(config, IComposerClient::Attribute::HEIGHT);
+    int32_t width = mComposerClient->getDisplayAttribute(
+        mPrimaryDisplay, config, IComposerClient::Attribute::WIDTH);
+    int32_t height = mComposerClient->getDisplayAttribute(
+        mPrimaryDisplay, config, IComposerClient::Attribute::HEIGHT);
     ASSERT_LT(0, width);
     ASSERT_LT(0, height);
 
-    setActiveConfig(config);
+    mComposerClient->setActiveConfig(mPrimaryDisplay, config);
 
-    auto ret = mComposerClient->getClientTargetSupport(
+    ASSERT_TRUE(mComposerClient->getClientTargetSupport(
         mPrimaryDisplay, width, height, PixelFormat::RGBA_8888,
-        Dataspace::UNKNOWN);
-    ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
+        Dataspace::UNKNOWN));
   }
 }
 
@@ -466,21 +294,22 @@
  * formats, and succeeds or fails correctly for optional attributes.
  */
 TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) {
-  std::vector<Config> configs = getDisplayConfigs();
+  std::vector<Config> configs =
+      mComposerClient->getDisplayConfigs(mPrimaryDisplay);
   for (auto config : configs) {
     const std::array<IComposerClient::Attribute, 3> requiredAttributes = {{
         IComposerClient::Attribute::WIDTH, IComposerClient::Attribute::HEIGHT,
         IComposerClient::Attribute::VSYNC_PERIOD,
     }};
     for (auto attribute : requiredAttributes) {
-      getDisplayAttribute(config, attribute);
+      mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, attribute);
     }
 
     const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
         IComposerClient::Attribute::DPI_X, IComposerClient::Attribute::DPI_Y,
     }};
     for (auto attribute : optionalAttributes) {
-      mComposerClient->getDisplayAttribute(
+      mComposerClient->getRaw()->getDisplayAttribute(
           mPrimaryDisplay, config, attribute,
           [&](const auto& tmpError, const auto&) {
             EXPECT_TRUE(tmpError == Error::NONE ||
@@ -494,19 +323,18 @@
  * Test IComposerClient::getHdrCapabilities.
  */
 TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) {
-  mComposerClient->getHdrCapabilities(
-      mPrimaryDisplay,
-      [&](const auto& tmpError, const auto&, const auto&, const auto&,
-          const auto&) { ASSERT_EQ(Error::NONE, tmpError); });
+  float maxLuminance;
+  float maxAverageLuminance;
+  float minLuminance;
+  mComposerClient->getHdrCapabilities(mPrimaryDisplay, &maxLuminance,
+                                      &maxAverageLuminance, &minLuminance);
 }
 
 /**
  * Test IComposerClient::setClientTargetSlotCount.
  */
 TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) {
-  auto ret = mComposerClient->setClientTargetSlotCount(mPrimaryDisplay,
-                                                       kBufferSlotCount);
-  ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
+  mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
 }
 
 /**
@@ -516,15 +344,11 @@
  * configs.
  */
 TEST_F(GraphicsComposerHidlTest, SetActiveConfig) {
-  std::vector<Config> configs = getDisplayConfigs();
+  std::vector<Config> configs =
+      mComposerClient->getDisplayConfigs(mPrimaryDisplay);
   for (auto config : configs) {
-    setActiveConfig(config);
-
-    mComposerClient->getActiveConfig(
-        mPrimaryDisplay, [&](const auto& tmpError, const auto& tmpConfig) {
-          EXPECT_EQ(Error::NONE, tmpError);
-          EXPECT_EQ(config, tmpConfig);
-        });
+    mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+    ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay));
   }
 }
 
@@ -534,9 +358,10 @@
  * Test that IComposerClient::setColorMode succeeds for all color modes.
  */
 TEST_F(GraphicsComposerHidlTest, SetColorMode) {
-  std::vector<ColorMode> modes = getColorModes();
+  std::vector<ColorMode> modes =
+      mComposerClient->getColorModes(mPrimaryDisplay);
   for (auto mode : modes) {
-    setColorMode(mode);
+    mComposerClient->setColorMode(mPrimaryDisplay, mode);
   }
 }
 
@@ -546,9 +371,19 @@
  * Test that IComposerClient::setPowerMode succeeds for all power modes.
  */
 TEST_F(GraphicsComposerHidlTest, SetPowerMode) {
-  std::vector<IComposerClient::PowerMode> modes = getPowerModes();
+  std::vector<IComposerClient::PowerMode> modes;
+  modes.push_back(IComposerClient::PowerMode::OFF);
+
+  if (mComposerClient->getDozeSupport(mPrimaryDisplay)) {
+    modes.push_back(IComposerClient::PowerMode::DOZE);
+    modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
+  }
+
+  // push ON last
+  modes.push_back(IComposerClient::PowerMode::ON);
+
   for (auto mode : modes) {
-    setPowerMode(mode);
+    mComposerClient->setPowerMode(mPrimaryDisplay, mode);
   }
 }
 
@@ -561,9 +396,9 @@
 TEST_F(GraphicsComposerHidlTest, SetVsyncEnabled) {
   mComposerCallback->setVsyncAllowed(true);
 
-  setVsyncEnabled(true);
+  mComposerClient->setVsyncEnabled(mPrimaryDisplay, true);
   usleep(60 * 1000);
-  setVsyncEnabled(false);
+  mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
 
   mComposerCallback->setVsyncAllowed(false);
 }
@@ -573,7 +408,10 @@
  protected:
   void SetUp() override {
     ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
-    ASSERT_NO_FATAL_FAILURE(SetUpGralloc());
+
+    ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
+    ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient());
+    ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>());
 
     mWriter = std::make_unique<CommandWriterBase>(1024);
     mReader = std::make_unique<CommandReader>();
@@ -583,80 +421,6 @@
     ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
   }
 
-  const native_handle_t* cloneBuffer(const native_handle_t* handle) {
-    auto clone = native_handle_clone(handle);
-    if (!clone) {
-      return nullptr;
-    }
-
-    GrallocError err = mMapper->retain(clone);
-    if (err != GrallocError::NONE) {
-      native_handle_close(clone);
-      native_handle_delete(const_cast<native_handle_t*>(clone));
-      return nullptr;
-    }
-
-    return clone;
-  }
-
-  const native_handle_t* allocate(
-      const IAllocatorClient::BufferDescriptorInfo& info) {
-    // create descriptor
-    GrallocError err = GrallocError::NO_RESOURCES;
-    BufferDescriptor descriptor;
-    mAllocatorClient->createDescriptor(
-        info, [&](const auto& tmpError, const auto& tmpDescriptor) {
-          err = tmpError;
-          descriptor = tmpDescriptor;
-        });
-    if (err != GrallocError::NONE) {
-      return nullptr;
-    }
-
-    // allocate buffer
-    hidl_vec<BufferDescriptor> descriptors;
-    hidl_vec<Buffer> buffers;
-    descriptors.setToExternal(&descriptor, 1);
-    err = GrallocError::NO_RESOURCES;
-    mAllocatorClient->allocate(
-        descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
-          err = tmpError;
-          buffers = tmpBuffers;
-        });
-    if ((err != GrallocError::NONE && err != GrallocError::NOT_SHARED) ||
-        buffers.size() != 1) {
-      mAllocatorClient->destroyDescriptor(descriptors[0]);
-      return nullptr;
-    }
-
-    // export handle
-    err = GrallocError::NO_RESOURCES;
-    const native_handle_t* handle = nullptr;
-    mAllocatorClient->exportHandle(
-        descriptors[0], buffers[0],
-        [&](const auto& tmpError, const auto& tmpHandle) {
-          err = tmpError;
-          if (err != GrallocError::NONE) {
-            return;
-          }
-
-          handle = cloneBuffer(tmpHandle.getNativeHandle());
-          if (!handle) {
-            err = GrallocError::NO_RESOURCES;
-            return;
-          }
-        });
-
-    mAllocatorClient->destroyDescriptor(descriptors[0]);
-    mAllocatorClient->free(buffers[0]);
-
-    if (err != GrallocError::NONE) {
-      return nullptr;
-    }
-
-    return handle;
-  }
-
   const native_handle_t* allocate() {
     IAllocatorClient::BufferDescriptorInfo info{};
     info.width = 64;
@@ -666,12 +430,7 @@
     info.producerUsageMask = static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
     info.consumerUsageMask = static_cast<uint64_t>(ConsumerUsage::CPU_READ);
 
-    return allocate(info);
-  }
-
-  void free(const native_handle_t* handle) {
-    auto ret = mMapper->release(handle);
-    ASSERT_EQ(GrallocError::NONE, static_cast<GrallocError>(ret));
+    return mMapper->allocate(mAllocatorClient, info);
   }
 
   void execute() {
@@ -682,20 +441,20 @@
         mWriter->writeQueue(&queueChanged, &commandLength, &commandHandles));
 
     if (queueChanged) {
-      auto ret =
-          mComposerClient->setInputCommandQueue(*mWriter->getMQDescriptor());
+      auto ret = mComposerClient->getRaw()->setInputCommandQueue(
+          *mWriter->getMQDescriptor());
       ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
       return;
     }
 
-    mComposerClient->executeCommands(
+    mComposerClient->getRaw()->executeCommands(
         commandLength, commandHandles,
         [&](const auto& tmpError, const auto& tmpOutQueueChanged,
             const auto& tmpOutLength, const auto& tmpOutHandles) {
           ASSERT_EQ(Error::NONE, tmpError);
 
           if (tmpOutQueueChanged) {
-            mComposerClient->getOutputCommandQueue(
+            mComposerClient->getRaw()->getOutputCommandQueue(
                 [&](const auto& tmpError, const auto& tmpDescriptor) {
                   ASSERT_EQ(Error::NONE, tmpError);
                   mReader->setMQDescriptor(tmpDescriptor);
@@ -748,25 +507,9 @@
   std::unique_ptr<CommandReader> mReader;
 
  private:
-  void SetUpGralloc() {
-    mAllocator = ::testing::VtsHalHidlTargetBaseTest::getService<IAllocator>();
-    ASSERT_NE(nullptr, mAllocator.get());
-
-    mAllocator->createClient([this](const auto& error, const auto& client) {
-      if (error == GrallocError::NONE) {
-        mAllocatorClient = client;
-      }
-    });
-    ASSERT_NE(nullptr, mAllocatorClient.get());
-
-    mMapper = ::testing::VtsHalHidlTargetBaseTest::getService<IMapper>();
-    ASSERT_NE(nullptr, mMapper.get());
-    ASSERT_FALSE(mMapper->isRemote());
-  }
-
-  sp<IAllocator> mAllocator;
-  sp<IAllocatorClient> mAllocatorClient;
-  sp<IMapper> mMapper;
+  std::unique_ptr<Allocator> mAllocator;
+  std::unique_ptr<AllocatorClient> mAllocatorClient;
+  std::unique_ptr<Mapper> mMapper;
 };
 
 /**
@@ -801,22 +544,23 @@
  * Test IComposerClient::Command::SET_OUTPUT_BUFFER.
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) {
-  auto handle = allocate();
-  ASSERT_NE(nullptr, handle);
-
-  Display display;
-  Error err = createVirtualDisplay(&display);
-  if (err == Error::UNSUPPORTED) {
+  if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
     GTEST_SUCCEED() << "no virtual display support";
     return;
   }
-  ASSERT_EQ(Error::NONE, err);
+
+  Display display;
+  PixelFormat format;
+  ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay(
+                              64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
+                              kBufferSlotCount, &format));
+
+  const native_handle_t* handle;
+  ASSERT_NO_FATAL_FAILURE(handle = allocate());
 
   mWriter->selectDisplay(display);
   mWriter->setOutputBuffer(0, handle, -1);
-
-  destroyVirtualDisplay(display);
-  free(handle);
+  execute();
 }
 
 /**
@@ -853,16 +597,14 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerCursorPosition(1, 1);
   mWriter->setLayerCursorPosition(0, 0);
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -873,16 +615,13 @@
   ASSERT_NE(nullptr, handle);
 
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerBuffer(0, handle, -1);
   execute();
-
-  destroyLayer(layer);
-  free(handle);
 }
 
 /**
@@ -890,8 +629,8 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   IComposerClient::Rect empty{0, 0, 0, 0};
   IComposerClient::Rect unit{0, 0, 1, 1};
@@ -902,8 +641,6 @@
   mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, unit));
   mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>());
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -911,8 +648,8 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
@@ -920,8 +657,6 @@
   mWriter->setLayerBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
   mWriter->setLayerBlendMode(IComposerClient::BlendMode::COVERAGE);
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -929,16 +664,14 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerColor(IComposerClient::Color{0xff, 0xff, 0xff, 0xff});
   mWriter->setLayerColor(IComposerClient::Color{0, 0, 0, 0});
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -946,8 +679,8 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
@@ -956,8 +689,6 @@
   mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
   mWriter->setLayerCompositionType(IComposerClient::Composition::CURSOR);
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -965,15 +696,13 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerDataspace(Dataspace::UNKNOWN);
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -981,15 +710,13 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerDisplayFrame(IComposerClient::Rect{0, 0, 1, 1});
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -997,23 +724,21 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerPlaneAlpha(0.0f);
   mWriter->setLayerPlaneAlpha(1.0f);
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
  * Test IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM.
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
-  if (!hasCapability(IComposer::Capability::SIDEBAND_STREAM)) {
+  if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) {
     GTEST_SUCCEED() << "no sideband stream support";
     return;
   }
@@ -1022,16 +747,13 @@
   ASSERT_NE(nullptr, handle);
 
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerSidebandStream(handle);
   execute();
-
-  destroyLayer(layer);
-  free(handle);
 }
 
 /**
@@ -1039,15 +761,13 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerSourceCrop(IComposerClient::FRect{0.0f, 0.0f, 1.0f, 1.0f});
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -1055,8 +775,8 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
@@ -1071,8 +791,6 @@
   mWriter->setLayerTransform(
       static_cast<Transform>(Transform::FLIP_V | Transform::ROT_90));
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -1080,8 +798,8 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   IComposerClient::Rect empty{0, 0, 0, 0};
   IComposerClient::Rect unit{0, 0, 1, 1};
@@ -1092,8 +810,6 @@
   mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, unit));
   mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>());
   execute();
-
-  destroyLayer(layer);
 }
 
 /**
@@ -1101,16 +817,14 @@
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) {
   Layer layer;
-  Error err = createLayer(&layer);
-  ASSERT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(
+      layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
 
   mWriter->selectDisplay(mPrimaryDisplay);
   mWriter->selectLayer(layer);
   mWriter->setLayerZOrder(10);
   mWriter->setLayerZOrder(0);
   execute();
-
-  destroyLayer(layer);
 }
 
 }  // namespace anonymous
diff --git a/graphics/mapper/2.0/default/GrallocMapper.cpp b/graphics/mapper/2.0/default/GrallocMapper.cpp
index 3b6460a..526aca2 100644
--- a/graphics/mapper/2.0/default/GrallocMapper.cpp
+++ b/graphics/mapper/2.0/default/GrallocMapper.cpp
@@ -127,7 +127,7 @@
 
 void GrallocMapperHal::initCapabilities()
 {
-    uint32_t count;
+    uint32_t count = 0;
     mDevice->getCapabilities(mDevice, &count, nullptr);
 
     std::vector<int32_t> caps(count);
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
index 24cd1be..8b3379f 100644
--- a/graphics/mapper/2.0/vts/functional/Android.bp
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -14,6 +14,27 @@
 // limitations under the License.
 //
 
+cc_library_static {
+    name: "libVtsHalGraphicsMapperTestUtils",
+    srcs: ["VtsHalGraphicsMapperTestUtils.cpp"],
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetBaseTest",
+        "libVtsHalGraphicsAllocatorTestUtils",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-O0",
+        "-g",
+    ],
+    export_include_dirs: ["."],
+}
+
 cc_test {
     name: "VtsHalGraphicsMapperV2_0TargetTest",
     srcs: ["VtsHalGraphicsMapperV2_0TargetTest.cpp"],
@@ -30,8 +51,15 @@
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.common@1.0",
     ],
-    static_libs: ["VtsHalHidlTargetBaseTest"],
+    static_libs: [
+        "libVtsHalGraphicsAllocatorTestUtils",
+        "libVtsHalGraphicsMapperTestUtils",
+        "VtsHalHidlTargetBaseTest",
+    ],
     cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
         "-O0",
         "-g",
     ]
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
new file mode 100644
index 0000000..fc26587
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetBaseTest.h>
+
+#include "VtsHalGraphicsMapperTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace tests {
+
+using android::hardware::graphics::allocator::V2_0::Buffer;
+using android::hardware::graphics::allocator::V2_0::BufferDescriptor;
+using android::hardware::graphics::allocator::V2_0::Error;
+
+Mapper::Mapper() { init(); }
+
+void Mapper::init() {
+  mMapper = ::testing::VtsHalHidlTargetBaseTest::getService<IMapper>();
+  ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
+  ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+}
+
+Mapper::~Mapper() {
+  for (auto it : mHandles) {
+    while (it.second) {
+      EXPECT_EQ(Error::NONE, mMapper->release(it.first))
+          << "failed to release handle " << it.first;
+      it.second--;
+    }
+  }
+  mHandles.clear();
+}
+
+sp<IMapper> Mapper::getRaw() const { return mMapper; }
+
+void Mapper::retain(const native_handle_t* handle) {
+  Error error = mMapper->retain(handle);
+  ASSERT_EQ(Error::NONE, error) << "failed to retain handle " << handle;
+
+  mHandles[handle]++;
+}
+
+void Mapper::release(const native_handle_t* handle) {
+  Error error = mMapper->release(handle);
+  ASSERT_EQ(Error::NONE, error) << "failed to release handle " << handle;
+
+  if (--mHandles[handle] == 0) {
+    mHandles.erase(handle);
+  }
+}
+
+Mapper::Dimensions Mapper::getDimensions(const native_handle_t* handle) {
+  Dimensions dimensions = {};
+  mMapper->getDimensions(handle, [&](const auto& tmpError, const auto& tmpWidth,
+                                     const auto& tmpHeight) {
+    ASSERT_EQ(Error::NONE, tmpError)
+        << "failed to get dimensions for handle " << handle;
+    dimensions.width = tmpWidth;
+    dimensions.height = tmpHeight;
+  });
+
+  return dimensions;
+}
+
+PixelFormat Mapper::getFormat(const native_handle_t* handle) {
+  PixelFormat format = static_cast<PixelFormat>(0);
+  mMapper->getFormat(handle, [&](const auto& tmpError, const auto& tmpFormat) {
+    ASSERT_EQ(Error::NONE, tmpError)
+        << "failed to get format for handle " << handle;
+    format = tmpFormat;
+  });
+
+  return format;
+}
+
+uint32_t Mapper::getLayerCount(const native_handle_t* handle) {
+  uint32_t count = 0;
+  mMapper->getLayerCount(
+      handle, [&](const auto& tmpError, const auto& tmpCount) {
+        ASSERT_EQ(Error::NONE, tmpError)
+            << "failed to get layer count for handle " << handle;
+        count = tmpCount;
+      });
+
+  return count;
+}
+
+uint64_t Mapper::getProducerUsageMask(const native_handle_t* handle) {
+  uint64_t usageMask = 0;
+  mMapper->getProducerUsageMask(
+      handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
+        ASSERT_EQ(Error::NONE, tmpError)
+            << "failed to get producer usage mask for handle " << handle;
+        usageMask = tmpUsageMask;
+      });
+
+  return usageMask;
+}
+
+uint64_t Mapper::getConsumerUsageMask(const native_handle_t* handle) {
+  uint64_t usageMask = 0;
+  mMapper->getConsumerUsageMask(
+      handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
+        ASSERT_EQ(Error::NONE, tmpError)
+            << "failed to get consumer usage mask for handle " << handle;
+        usageMask = tmpUsageMask;
+      });
+
+  return usageMask;
+}
+
+BackingStore Mapper::getBackingStore(const native_handle_t* handle) {
+  BackingStore backingStore = 0;
+  mMapper->getBackingStore(
+      handle, [&](const auto& tmpError, const auto& tmpBackingStore) {
+        ASSERT_EQ(Error::NONE, tmpError)
+            << "failed to get backing store for handle " << handle;
+        backingStore = tmpBackingStore;
+      });
+
+  return backingStore;
+}
+
+uint32_t Mapper::getStride(const native_handle_t* handle) {
+  uint32_t stride = 0;
+  mMapper->getStride(handle, [&](const auto& tmpError, const auto& tmpStride) {
+    ASSERT_EQ(Error::NONE, tmpError)
+        << "failed to get stride for handle " << handle;
+    stride = tmpStride;
+  });
+
+  return stride;
+}
+
+void* Mapper::lock(const native_handle_t* handle, uint64_t producerUsageMask,
+                   uint64_t consumerUsageMask,
+                   const IMapper::Rect& accessRegion, int acquireFence) {
+  NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
+  native_handle_t* acquireFenceHandle = nullptr;
+  if (acquireFence >= 0) {
+    acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
+    acquireFenceHandle->data[0] = acquireFence;
+  }
+
+  void* data = nullptr;
+  mMapper->lock(
+      handle, producerUsageMask, consumerUsageMask, accessRegion,
+      acquireFenceHandle, [&](const auto& tmpError, const auto& tmpData) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to lock handle " << handle;
+        data = tmpData;
+      });
+
+  if (acquireFence >= 0) {
+    close(acquireFence);
+  }
+
+  return data;
+}
+
+FlexLayout Mapper::lockFlex(const native_handle_t* handle,
+                            uint64_t producerUsageMask,
+                            uint64_t consumerUsageMask,
+                            const IMapper::Rect& accessRegion,
+                            int acquireFence) {
+  NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
+  native_handle_t* acquireFenceHandle = nullptr;
+  if (acquireFence >= 0) {
+    acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
+    acquireFenceHandle->data[0] = acquireFence;
+  }
+
+  FlexLayout layout = {};
+  mMapper->lockFlex(handle, producerUsageMask, consumerUsageMask, accessRegion,
+                    acquireFenceHandle,
+                    [&](const auto& tmpError, const auto& tmpLayout) {
+                      ASSERT_EQ(Error::NONE, tmpError)
+                          << "failed to lockFlex handle " << handle;
+                      layout = tmpLayout;
+                    });
+
+  if (acquireFence >= 0) {
+    close(acquireFence);
+  }
+
+  return layout;
+}
+
+int Mapper::unlock(const native_handle_t* handle) {
+  int releaseFence = -1;
+  mMapper->unlock(handle, [&](const auto& tmpError,
+                              const auto& tmpReleaseFence) {
+    ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock handle " << handle;
+
+    auto handle = tmpReleaseFence.getNativeHandle();
+    if (handle) {
+      ASSERT_EQ(0, handle->numInts) << "invalid fence handle " << handle;
+      if (handle->numFds == 1) {
+        releaseFence = dup(handle->data[0]);
+        ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+      } else {
+        ASSERT_EQ(0, handle->numFds) << " invalid fence handle " << handle;
+      }
+    }
+  });
+
+  return releaseFence;
+}
+
+const native_handle_t* Mapper::allocate(
+    std::unique_ptr<AllocatorClient>& allocatorClient,
+    const IAllocatorClient::BufferDescriptorInfo& info) {
+  BufferDescriptor descriptor = allocatorClient->createDescriptor(info);
+  if (::testing::Test::HasFatalFailure()) {
+    return nullptr;
+  }
+
+  Buffer buffer = allocatorClient->allocate(descriptor);
+  if (::testing::Test::HasFatalFailure()) {
+    allocatorClient->destroyDescriptor(descriptor);
+    return nullptr;
+  }
+
+  const native_handle_t* handle =
+      allocatorClient->exportHandle(descriptor, buffer);
+  if (handle) {
+    retain(handle);
+  }
+
+  allocatorClient->free(buffer);
+  allocatorClient->destroyDescriptor(descriptor);
+
+  return handle;
+}
+
+}  // namespace tests
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
new file mode 100644
index 0000000..c186b00
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS
+#define VTS_HAL_GRAPHICS_MAPPER_UTILS
+
+#include <memory>
+#include <unordered_map>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <utils/StrongPointer.h>
+
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace tests {
+
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::allocator::V2_0::IAllocatorClient;
+using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient;
+
+// A wrapper to IMapper.
+class Mapper {
+ public:
+  Mapper();
+  ~Mapper();
+
+  sp<IMapper> getRaw() const;
+
+  void retain(const native_handle_t* handle);
+  void release(const native_handle_t* handle);
+
+  struct Dimensions {
+    uint32_t width;
+    uint32_t height;
+  };
+  Dimensions getDimensions(const native_handle_t* handle);
+
+  PixelFormat getFormat(const native_handle_t* handle);
+  uint32_t getLayerCount(const native_handle_t* handle);
+  uint64_t getProducerUsageMask(const native_handle_t* handle);
+  uint64_t getConsumerUsageMask(const native_handle_t* handle);
+  BackingStore getBackingStore(const native_handle_t* handle);
+  uint32_t getStride(const native_handle_t* handle);
+
+  // We use fd instead of hidl_handle in these functions to pass fences
+  // in and out of the mapper.  The ownership of the fd is always transferred
+  // with each of these functions.
+  void* lock(const native_handle_t* handle, uint64_t producerUsageMask,
+             uint64_t consumerUsageMask, const IMapper::Rect& accessRegion,
+             int acquireFence);
+  FlexLayout lockFlex(const native_handle_t* handle, uint64_t producerUsageMask,
+                      uint64_t consumerUsageMask,
+                      const IMapper::Rect& accessRegion, int acquireFence);
+  int unlock(const native_handle_t* handle);
+
+  // Requests AllocatorClient to allocate a buffer, export the handle, and
+  // register the handle with mapper.
+  const native_handle_t* allocate(
+      std::unique_ptr<AllocatorClient>& allocatorClient,
+      const IAllocatorClient::BufferDescriptorInfo& info);
+
+ private:
+  void init();
+
+  sp<IMapper> mMapper;
+
+  // Keep track of all registered (retained) handles.  When a test fails with
+  // ASSERT_*, the destructor will release the handles for the test.
+  std::unordered_map<const native_handle_t*, uint64_t> mHandles;
+};
+
+}  // namespace tests
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // VTS_HAL_GRAPHICS_MAPPER_UTILS
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index b2a37dd..bd8315e 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -17,10 +17,9 @@
 #define LOG_TAG "graphics_mapper_hidl_hal_test"
 
 #include <android-base/logging.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <VtsHalHidlTargetBaseTest.h>
 #include <sync/sync.h>
+#include "VtsHalGraphicsMapperTestUtils.h"
 
 namespace android {
 namespace hardware {
@@ -31,24 +30,14 @@
 namespace {
 
 using namespace android::hardware::graphics::allocator::V2_0;
-using namespace android::hardware::graphics::common::V1_0;
+using namespace android::hardware::graphics::allocator::V2_0::tests;
 
 class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
  protected:
   void SetUp() override {
-    mAllocator = ::testing::VtsHalHidlTargetBaseTest::getService<IAllocator>();
-    ASSERT_NE(mAllocator, nullptr);
-
-    mAllocator->createClient([this](const auto& error, const auto& client) {
-      if (error == Error::NONE) {
-        mAllocatorClient = client;
-      }
-    });
-    ASSERT_NE(mAllocatorClient, nullptr);
-
-    mMapper = ::testing::VtsHalHidlTargetBaseTest::getService<IMapper>();
-    ASSERT_NE(nullptr, mMapper.get());
-    ASSERT_FALSE(mMapper->isRemote());
+    ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
+    ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient());
+    ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>());
 
     mDummyDescriptorInfo.width = 64;
     mDummyDescriptorInfo.height = 64;
@@ -62,134 +51,51 @@
 
   void TearDown() override {}
 
-  const native_handle_t* allocate(
-      const IAllocatorClient::BufferDescriptorInfo& info) {
-    // create descriptor
-    Error err = Error::NO_RESOURCES;
-    BufferDescriptor descriptor;
-    mAllocatorClient->createDescriptor(
-        info, [&](const auto& tmpError, const auto& tmpDescriptor) {
-          err = tmpError;
-          descriptor = tmpDescriptor;
-        });
-    if (err != Error::NONE) {
-      return nullptr;
-    }
-
-    // allocate buffer
-    hidl_vec<BufferDescriptor> descriptors;
-    hidl_vec<Buffer> buffers;
-    descriptors.setToExternal(&descriptor, 1);
-    err = Error::NO_RESOURCES;
-    mAllocatorClient->allocate(
-        descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
-          err = tmpError;
-          buffers = tmpBuffers;
-        });
-    if ((err != Error::NONE && err != Error::NOT_SHARED) ||
-        buffers.size() != 1) {
-      mAllocatorClient->destroyDescriptor(descriptors[0]);
-      return nullptr;
-    }
-
-    // export handle
-    err = Error::NO_RESOURCES;
-    const native_handle_t* handle = nullptr;
-    mAllocatorClient->exportHandle(
-        descriptors[0], buffers[0],
-        [&](const auto& tmpError, const auto& tmpHandle) {
-          err = tmpError;
-          if (err != Error::NONE) {
-            return;
-          }
-
-          handle = native_handle_clone(tmpHandle);
-          if (!handle) {
-            err = Error::NO_RESOURCES;
-            return;
-          }
-
-          err = mMapper->retain(handle);
-          if (err != Error::NONE) {
-            native_handle_close(handle);
-            native_handle_delete(const_cast<native_handle_t*>(handle));
-            handle = nullptr;
-          }
-        });
-
-    mAllocatorClient->destroyDescriptor(descriptors[0]);
-    mAllocatorClient->free(buffers[0]);
-
-    if (err != Error::NONE) {
-      return nullptr;
-    }
-
-    return handle;
-  }
-
-  sp<IMapper> mMapper;
-
+  std::unique_ptr<Allocator> mAllocator;
+  std::unique_ptr<AllocatorClient> mAllocatorClient;
+  std::unique_ptr<Mapper> mMapper;
   IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
-
- private:
-  sp<IAllocator> mAllocator;
-  sp<IAllocatorClient> mAllocatorClient;
 };
 
 /**
  * Test IMapper::retain and IMapper::release.
  */
 TEST_F(GraphicsMapperHidlTest, RetainRelease) {
-  const native_handle_t* buffer = allocate(mDummyDescriptorInfo);
-  ASSERT_NE(buffer, nullptr);
+  const native_handle_t* buffer;
+  ASSERT_NO_FATAL_FAILURE(
+      buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
 
   const int maxRefs = 10;
   for (int i = 0; i < maxRefs; i++) {
-    auto err = mMapper->retain(buffer);
-    EXPECT_EQ(Error::NONE, err);
+    ASSERT_NO_FATAL_FAILURE(mMapper->retain(buffer));
   }
   for (int i = 0; i < maxRefs; i++) {
-    auto err = mMapper->release(buffer);
-    EXPECT_EQ(Error::NONE, err);
+    ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
   }
 
-  auto err = mMapper->release(buffer);
-  EXPECT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
 }
 
 /**
  * Test IMapper::get* getters.
  */
 TEST_F(GraphicsMapperHidlTest, Getters) {
-  const native_handle_t* buffer = allocate(mDummyDescriptorInfo);
-  ASSERT_NE(buffer, nullptr);
+  const native_handle_t* buffer;
+  ASSERT_NO_FATAL_FAILURE(
+      buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
 
-  Error err = Error::NO_RESOURCES;
-  IAllocatorClient::BufferDescriptorInfo info{};
-  mMapper->getDimensions(buffer, [&](const auto& tmpError, const auto& tmpWidth,
-                                     const auto& tmpHeight) {
-    err = tmpError;
-    info.width = tmpWidth;
-    info.height = tmpHeight;
-  });
-  EXPECT_EQ(Error::NONE, err);
-  mMapper->getFormat(buffer, [&](const auto& tmpError, const auto& tmpFormat) {
-    err = tmpError;
-    info.format = tmpFormat;
-  });
-  EXPECT_EQ(Error::NONE, err);
-  mMapper->getProducerUsageMask(
-      buffer, [&](const auto& tmpError, const auto& tmpUsage) {
-        err = tmpError;
-        info.producerUsageMask = tmpUsage;
-      });
-  EXPECT_EQ(Error::NONE, err);
-  mMapper->getConsumerUsageMask(
-      buffer, [&](const auto& tmpError, const auto& tmpUsage) {
-        err = tmpError;
-        info.consumerUsageMask = tmpUsage;
-      });
-  EXPECT_EQ(Error::NONE, err);
+  IAllocatorClient::BufferDescriptorInfo info = {};
+
+  Mapper::Dimensions dimensions;
+  ASSERT_NO_FATAL_FAILURE(dimensions = mMapper->getDimensions(buffer));
+  info.width = dimensions.width;
+  info.height = dimensions.height;
+
+  ASSERT_NO_FATAL_FAILURE(info.format = mMapper->getFormat(buffer));
+  ASSERT_NO_FATAL_FAILURE(info.producerUsageMask =
+                              mMapper->getProducerUsageMask(buffer));
+  ASSERT_NO_FATAL_FAILURE(info.consumerUsageMask =
+                              mMapper->getConsumerUsageMask(buffer));
 
   EXPECT_EQ(mDummyDescriptorInfo.width, info.width);
   EXPECT_EQ(mDummyDescriptorInfo.height, info.height);
@@ -197,24 +103,11 @@
   EXPECT_EQ(mDummyDescriptorInfo.producerUsageMask, info.producerUsageMask);
   EXPECT_EQ(mDummyDescriptorInfo.consumerUsageMask, info.consumerUsageMask);
 
-  BackingStore store = 0;
-  mMapper->getBackingStore(buffer,
-                           [&](const auto& tmpError, const auto& tmpStore) {
-                             err = tmpError;
-                             store = tmpStore;
-                           });
-  EXPECT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(mMapper->getBackingStore(buffer));
 
-  uint32_t stride = 0;
-  mMapper->getStride(buffer, [&](const auto& tmpError, const auto& tmpStride) {
-    err = tmpError;
-    stride = tmpStride;
-  });
-  EXPECT_EQ(Error::NONE, err);
+  uint32_t stride;
+  ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
   EXPECT_LE(info.width, stride);
-
-  err = mMapper->release(buffer);
-  EXPECT_EQ(Error::NONE, err);
 }
 
 /**
@@ -222,79 +115,113 @@
  */
 TEST_F(GraphicsMapperHidlTest, LockBasic) {
   const auto& info = mDummyDescriptorInfo;
-  const native_handle_t* buffer = allocate(info);
-  ASSERT_NE(buffer, nullptr);
 
-  Error err = Error::NO_RESOURCES;
-  uint32_t stride = 0;
-  mMapper->getStride(buffer, [&](const auto& tmpError, const auto& tmpStride) {
-    err = tmpError;
-    stride = tmpStride;
-  });
-  EXPECT_EQ(Error::NONE, err);
+  const native_handle_t* buffer;
+  ASSERT_NO_FATAL_FAILURE(
+      buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
+
+  uint32_t stride;
+  ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
 
   // lock buffer for writing
   const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
                              static_cast<int32_t>(info.height)};
-  hidl_handle acquireFence(nullptr);
+  int fence = -1;
   uint32_t* data;
-  err = Error::NO_RESOURCES;
-  mMapper->lock(buffer, info.producerUsageMask, 0, region, acquireFence,
-          [&](const auto& tmpError, const auto& tmpData) {
-            err = tmpError;
-            data = static_cast<uint32_t*>(tmpData);
-          });
+  ASSERT_NO_FATAL_FAILURE(
+      data = static_cast<uint32_t*>(
+          mMapper->lock(buffer, info.producerUsageMask, 0, region, fence)));
 
-  if (err == Error::NONE) {
-    for (uint32_t y = 0; y < info.height; y++) {
-      for (uint32_t x = 0; x < info.width; x++) {
-        data[stride * y + x] = info.height * y + x;
-      }
+  for (uint32_t y = 0; y < info.height; y++) {
+    for (uint32_t x = 0; x < info.width; x++) {
+      data[stride * y + x] = info.height * y + x;
     }
-  } else {
-    EXPECT_EQ(Error::NONE, err);
   }
 
-  err = Error::NO_RESOURCES;
-  mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
-            err = tmpError;
-            auto handle = tmpReleaseFence.getNativeHandle();
-            if (handle && handle->numFds == 1) {
-                sync_wait(handle->data[0], -1);
-                close(handle->data[0]);
-            }
-          });
-  EXPECT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
 
   // lock buffer for reading
-  mMapper->lock(buffer, 0, info.consumerUsageMask, region, acquireFence,
-          [&](const auto& tmpError, const auto& tmpData) {
-            err = tmpError;
-            data = static_cast<uint32_t*>(tmpData);
-          });
-  if (err == Error::NONE) {
-    for (uint32_t y = 0; y < info.height; y++) {
-      for (uint32_t x = 0; x < info.width; x++) {
-        EXPECT_EQ(info.height * y + x, data[stride * y + x]);
-      }
+  ASSERT_NO_FATAL_FAILURE(
+      data = static_cast<uint32_t*>(
+          mMapper->lock(buffer, 0, info.consumerUsageMask, region, fence)));
+  for (uint32_t y = 0; y < info.height; y++) {
+    for (uint32_t x = 0; x < info.width; x++) {
+      EXPECT_EQ(info.height * y + x, data[stride * y + x]);
     }
-  } else {
-    EXPECT_EQ(Error::NONE, err);
   }
 
-  err = Error::NO_RESOURCES;
-  mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
-            err = tmpError;
-            auto handle = tmpReleaseFence.getNativeHandle();
-            if (handle && handle->numFds == 1) {
-                sync_wait(handle->data[0], -1);
-                close(handle->data[0]);
-            }
-          });
-  EXPECT_EQ(Error::NONE, err);
+  ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+  if (fence >= 0) {
+    close(fence);
+  }
+}
 
-  err = mMapper->release(buffer);
-  EXPECT_EQ(Error::NONE, err);
+/**
+ * Test IMapper::lockFlex.  This locks a YV12 buffer, and makes sure we can
+ * write to and read from it.
+ */
+TEST_F(GraphicsMapperHidlTest, LockFlexBasic) {
+  auto info = mDummyDescriptorInfo;
+  info.format = PixelFormat::YV12;
+
+  const native_handle_t* buffer;
+  ASSERT_NO_FATAL_FAILURE(buffer = mMapper->allocate(mAllocatorClient, info));
+
+  // lock buffer for writing
+  const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                             static_cast<int32_t>(info.height)};
+  int fence = -1;
+  FlexLayout layout;
+  ASSERT_NO_FATAL_FAILURE(
+      layout =
+          mMapper->lockFlex(buffer, info.producerUsageMask, 0, region, fence));
+  ASSERT_EQ(FlexFormat::YCBCR, layout.format);
+  ASSERT_EQ(3u, layout.planes.size());
+
+  const auto y_stride = layout.planes[0].vIncrement;
+  const auto c_stride = layout.planes[1].vIncrement;
+  auto y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
+  auto cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
+  auto cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
+
+  for (uint32_t y = 0; y < info.height; y++) {
+    for (uint32_t x = 0; x < info.width; x++) {
+      auto val = static_cast<uint8_t>(info.height * y + x);
+
+      y_data[y_stride * y + x] = val;
+      if (y % 2 == 0 && x % 2 == 0) {
+        cb_data[c_stride * y / 2 + x / 2] = val;
+        cr_data[c_stride * y / 2 + x / 2] = val;
+      }
+    }
+  }
+
+  ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+
+  // lock buffer for reading
+  ASSERT_NO_FATAL_FAILURE(
+      layout =
+          mMapper->lockFlex(buffer, 0, info.consumerUsageMask, region, fence));
+
+  y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
+  cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
+  cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
+  for (uint32_t y = 0; y < info.height; y++) {
+    for (uint32_t x = 0; x < info.width; x++) {
+      auto val = static_cast<uint8_t>(info.height * y + x);
+
+      EXPECT_EQ(val, y_data[y_stride * y + x]);
+      if (y % 2 == 0 && x % 2 == 0) {
+        EXPECT_EQ(val, cb_data[c_stride * y / 2 + x / 2]);
+        EXPECT_EQ(val, cr_data[c_stride * y / 2 + x / 2]);
+      }
+    }
+  }
+
+  ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+  if (fence >= 0) {
+    close(fence);
+  }
 }
 
 }  // namespace anonymous
diff --git a/media/omx/1.0/IGraphicBufferSource.hal b/media/omx/1.0/IGraphicBufferSource.hal
index 4dbfd32..62073ad 100644
--- a/media/omx/1.0/IGraphicBufferSource.hal
+++ b/media/omx/1.0/IGraphicBufferSource.hal
@@ -29,25 +29,25 @@
  */
 interface IGraphicBufferSource {
 
-    configure(IOmxNode omxNode, Dataspace dataspace);
+    configure(IOmxNode omxNode, Dataspace dataspace) generates (Status status);
 
-    setSuspend(bool suspend, int64_t timeUs);
+    setSuspend(bool suspend, int64_t timeUs) generates (Status status);
 
-    setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs);
+    setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) generates (Status status);
 
-    setMaxFps(float maxFps);
+    setMaxFps(float maxFps) generates (Status status);
 
-    setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs);
+    setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) generates (Status status);
 
-    setStartTimeUs(int64_t startTimeUs);
+    setStartTimeUs(int64_t startTimeUs) generates (Status status);
 
-    setStopTimeUs(int64_t stopTimeUs);
+    setStopTimeUs(int64_t stopTimeUs) generates (Status status);
 
-    setColorAspects(ColorAspects aspects);
+    setColorAspects(ColorAspects aspects) generates (Status status);
 
-    setTimeOffsetUs(int64_t timeOffsetUs);
+    setTimeOffsetUs(int64_t timeOffsetUs) generates (Status status);
 
-    signalEndOfInputStream();
+    signalEndOfInputStream() generates (Status status);
 
 };
 
diff --git a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
index 5b6089d..4aa6d7e 100644
--- a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
+++ b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
@@ -325,18 +325,42 @@
 }
 
 /*
+ * PowerCycleAfterClose:
+ * Calls powerCycle() after close()
+ * Checks status
+ */
+TEST_F(NfcHidlTest, PowerCycleAfterClose) {
+  EXPECT_EQ(NfcStatus::OK, nfc_->close());
+  // Wait for CLOSE_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+
+  EXPECT_EQ(NfcStatus::FAILED, nfc_->powerCycle());
+
+  EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+  // Wait for OPEN_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
+/*
  * CoreInitialized:
- * Calls coreInitialized()
+ * Calls coreInitialized() with different data
  * Waits for NfcEvent.POST_INIT_CPLT
  */
 TEST_F(NfcHidlTest, CoreInitialized) {
   NfcData data;
   data.resize(1);
-  data[0] = 0;
-  EXPECT_EQ(NfcStatus::OK, nfc_->coreInitialized(data));
-  // Wait for NfcEvent.POST_INIT_CPLT
-  EXPECT_EQ(std::cv_status::no_timeout, wait());
-  EXPECT_EQ(NfcEvent::POST_INIT_CPLT, last_event_);
+  for (int i = 0; i <= 6; i++)
+  {
+    data[0] = i;
+    EXPECT_EQ(NfcStatus::OK, nfc_->coreInitialized(data));
+    // Wait for NfcEvent.POST_INIT_CPLT
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(NfcEvent::POST_INIT_CPLT, last_event_);
+  }
 }
 
 /*
@@ -348,6 +372,27 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->controlGranted());
 }
 
+/*
+ * ControlGrantedAfterClose:
+ * Call controlGranted() after close
+ * Checks the return value
+ */
+TEST_F(NfcHidlTest, ControlGrantedAfterClose) {
+  EXPECT_EQ(NfcStatus::OK, nfc_->close());
+  // Wait for CLOSE_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+
+  EXPECT_EQ(NfcStatus::OK, nfc_->controlGranted());
+
+  EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+  // Wait for OPEN_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
 /* PreDiscover:
  * Calls prediscover()
  * Checks the return value
@@ -356,6 +401,59 @@
   EXPECT_EQ(NfcStatus::OK, nfc_->prediscover());
 }
 
+/*
+ * PreDiscoverAfterClose:
+ * Call prediscover() after close
+ * Checks the return value
+ */
+TEST_F(NfcHidlTest, PreDiscoverAfterClose) {
+  EXPECT_EQ(NfcStatus::OK, nfc_->close());
+  // Wait for CLOSE_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+
+  EXPECT_EQ(NfcStatus::OK, nfc_->prediscover());
+
+  EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+  // Wait for OPEN_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
+/*
+ * CloseAfterClose:
+ * Calls close() multiple times
+ * Checks status
+ */
+TEST_F(NfcHidlTest, CloseAfterClose) {
+  EXPECT_EQ(NfcStatus::OK, nfc_->close());
+  // Wait for CLOSE_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+
+  EXPECT_EQ(NfcStatus::FAILED, nfc_->close());
+
+  EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+  // Wait for OPEN_CPLT event
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+  EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
+
+/*
+ * OpenAfterOpen:
+ * Calls open() multiple times
+ * Checks status
+ */
+TEST_F(NfcHidlTest, OpenAfterOpen) {
+  EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+  EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+}
+
 int main(int argc, char** argv) {
   ::testing::AddGlobalTestEnvironment(new NfcHidlEnvironment);
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/radio/1.0/IRadio.hal b/radio/1.0/IRadio.hal
index a8c9d93..b3e3e98 100644
--- a/radio/1.0/IRadio.hal
+++ b/radio/1.0/IRadio.hal
@@ -731,20 +731,6 @@
     oneway getDataCallList(int32_t serial);
 
     /*
-     * Indicates the current state of the screen. When the screen is off, the
-     * Radio must notify the baseband to suppress certain notifications (eg,
-     * signal strength and changes in LAC/CID or BID/SID/NID/latitude/longitude)
-     * in an effort to conserve power. These notifications must resume when the
-     * screen is on.
-     *
-     * @param serial Serial number of request.
-     * @param enable true = screen on, false = screen off.
-     *
-     * Response function is IRadioResponse.sendScreenStateResponse()
-     */
-    oneway sendScreenState(int32_t serial, bool enable);
-
-    /*
      * Enables/disables supplementary service related notifications from the network.
      * Notifications are reported via unsolSuppSvcNotification().
      *
diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal
index 11a1d03..cd0899a 100644
--- a/radio/1.0/IRadioResponse.hal
+++ b/radio/1.0/IRadioResponse.hal
@@ -928,17 +928,6 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:GENERIC_FAILURE
-     */
-    oneway sendScreenStateResponse(RadioResponseInfo info);
-
-    /*
-     * @param info Response info struct containing response type, serial no. and error
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SIM_BUSY
      *   RadioError:NO_MEMORY
      *   RadioError:SYSTEM_ERR
diff --git a/radio/1.0/vts/functional/Android.bp b/radio/1.0/vts/functional/Android.bp
index 10bd725..3872932 100644
--- a/radio/1.0/vts/functional/Android.bp
+++ b/radio/1.0/vts/functional/Android.bp
@@ -19,6 +19,7 @@
     srcs: ["radio_hidl_hal_test.cpp",
            "radio_response.cpp",
            "radio_hidl_hal_icc.cpp",
+           "radio_hidl_hal_sms.cpp",
            "VtsHalRadioV1_0TargetTest.cpp"],
     shared_libs: [
         "libbase",
@@ -35,4 +36,4 @@
         "-O0",
         "-g",
     ],
-}
\ No newline at end of file
+}
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
new file mode 100644
index 0000000..5bf7ae2
--- /dev/null
+++ b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include<radio_hidl_hal_utils.h>
+
+using namespace ::android::hardware::radio::V1_0;
+
+/*
+ * Test IRadio.sendSms() for the response returned.
+ */
+TEST_F(RadioHidlTest, sendSms) {
+    int serial = 0;
+    GsmSmsMessage msg;
+    msg.smscPdu = "";
+    msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
+
+    radio->sendSms(++serial, msg);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::INVALID_STATE, radioRsp->rspInfo.error);
+        EXPECT_EQ(0, radioRsp->sendSmsResult.errorCode);
+    } else {
+        EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error);
+        EXPECT_EQ("", radioRsp->sendSmsResult.ackPDU);
+        EXPECT_EQ(-1, radioRsp->sendSmsResult.errorCode);
+    }
+}
+
+/*
+ * Test IRadio.sendSMSExpectMore() for the response returned.
+ */
+TEST_F(RadioHidlTest, sendSMSExpectMore) {
+    int serial = 0;
+    GsmSmsMessage msg;
+    msg.smscPdu = "";
+    msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
+
+    radio->sendSMSExpectMore(++serial, msg);
+
+    // TODO(shuoq): add more test for this API when inserted sim card is considered
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::INVALID_STATE, radioRsp->rspInfo.error);
+    } else {
+        EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error);
+        EXPECT_EQ("", radioRsp->sendSmsResult.ackPDU);
+        EXPECT_EQ(-1, radioRsp->sendSmsResult.errorCode);
+    }
+}
+
+/*
+ * Test IRadio.acknowledgeLastIncomingGsmSms() for the response returned.
+ */
+TEST_F(RadioHidlTest, acknowledgeLastIncomingGsmSms) {
+    int serial = 0;
+    bool success = true;
+
+    radio->acknowledgeLastIncomingGsmSms(++serial, success,
+        SmsAcknowledgeFailCause::MEMORY_CAPACITY_EXCEEDED);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::INVALID_STATE, radioRsp->rspInfo.error);
+    } else {
+        // TODO(shuoq): Will test right behavior when inserted sim card is considered
+    }
+}
+
+/*
+ * Test IRadio.acknowledgeIncomingGsmSmsWithPdu() for the response returned.
+ */
+TEST_F(RadioHidlTest, acknowledgeIncomingGsmSmsWithPdu) {
+    int serial = 0;
+    bool success = true;
+    std::string ackPdu = "";
+
+    radio->acknowledgeIncomingGsmSmsWithPdu(++serial, success, ackPdu);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        // TODO(shuoq): Will test right behavior when inserted sim card is considered
+    }
+}
+
+/*
+ * Test IRadio.sendCdmaSms() for the response returned.
+ */
+TEST_F(RadioHidlTest, sendCdmaSms) {
+    int serial = 0;
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT;
+    cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK;
+    cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>) {11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>) {};
+
+    // Create a CdmaSmsMessage
+    android::hardware::radio::V1_0::CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData = (std::vector<uint8_t>)
+        {15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    radio->sendCdmaSms(++serial, cdmaSmsMessage);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        // TODO(shuoq): radioRsp->sendSmsResult needs to be investigated when Sim card is in
+    }
+}
+
+/*
+ * Test IRadio.acknowledgeLastIncomingCdmaSms() for the response returned.
+ */
+TEST_F(RadioHidlTest, acknowledgeLastIncomingCdmaSms) {
+    int serial = 0;
+
+    // Create a CdmaSmsAck
+    CdmaSmsAck cdmaSmsAck;
+    cdmaSmsAck.errorClass = CdmaSmsErrorClass::NO_ERROR;
+    cdmaSmsAck.smsCauseCode = 1;
+
+    radio->acknowledgeLastIncomingCdmaSms(++serial, cdmaSmsAck);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::NO_SMS_TO_ACK, radioRsp->rspInfo.error);
+    } else {
+        EXPECT_EQ(RadioError::NO_SMS_TO_ACK, radioRsp->rspInfo.error);
+    }
+}
+
+/*
+ * Test IRadio.sendImsSms() for the response returned.
+ */
+TEST_F(RadioHidlTest, sendImsSms) {
+    int serial = 1;
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT;
+    cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK;
+    cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>) {11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>) {};
+
+    // Create a CdmaSmsMessage
+    CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData = (std::vector<uint8_t>)
+        {15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    // Creata an ImsSmsMessage
+    ImsSmsMessage msg;
+    msg.tech = RadioTechnologyFamily::THREE_GPP2;
+    msg.retry = false;
+    msg.messageRef = 0;
+    msg.cdmaMessage = (std::vector<CdmaSmsMessage>) {cdmaSmsMessage};
+    msg.gsmMessage = (std::vector<GsmSmsMessage>) {};
+
+    radio->sendImsSms(serial, msg);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::INVALID_ARGUMENTS, radioRsp->rspInfo.error);
+    } else {
+        EXPECT_EQ(RadioError::INVALID_ARGUMENTS, radioRsp->rspInfo.error);
+        // TODO(shuoq): radioRsp->sendSmsResult needs to be investigated when sim card is in
+    }
+}
+
+/*
+ * Test IRadio.getSmscAddress() for the response returned.
+ */
+TEST_F(RadioHidlTest, getSmscAddress) {
+    int serial = 0;
+
+    radio->getSmscAddress(++serial);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error);
+        // TODO(shuoq): radioRsp->smscAddress needs to be investigated when Sim card is in
+    }
+}
+
+/*
+ * Test IRadio.setSmscAddress() for the response returned.
+ */
+TEST_F(RadioHidlTest, setSmscAddress) {
+    int serial = 0;
+    hidl_string address = hidl_string("smscAddress");
+
+    radio->setSmscAddress(++serial, address);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::INVALID_SMS_FORMAT, radioRsp->rspInfo.error);
+    } else {
+        EXPECT_EQ(RadioError::INVALID_SMS_FORMAT, radioRsp->rspInfo.error);
+    }
+}
+
+/*
+ * Test IRadio.writeSmsToSim() for the response returned.
+ */
+TEST_F(RadioHidlTest, writeSmsToSim) {
+    int serial = 0;
+    SmsWriteArgs smsWriteArgs;
+    smsWriteArgs.status = SmsWriteArgsStatus::REC_UNREAD;
+    smsWriteArgs.smsc = "";
+    smsWriteArgs.pdu = "01000b916105770203f3000006d4f29c3e9b01";
+
+    radio->writeSmsToSim(++serial, smsWriteArgs);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        // TODO(shuoq): radioRsp->writeSmsToSimIndex needs to be investigated when Sim card is in
+    }
+}
+
+/*
+ * Test IRadio.deleteSmsOnSim() for the response returned.
+ */
+TEST_F(RadioHidlTest, deleteSmsOnSim) {
+    int serial = 0;
+    int index = 1;
+
+    radio->deleteSmsOnSim(++serial, index);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        EXPECT_EQ(RadioError::NO_SUCH_ENTRY, radioRsp->rspInfo.error);
+    }
+}
+
+/*
+ * Test IRadio.writeSmsToRuim() for the response returned.
+ */
+TEST_F(RadioHidlTest, writeSmsToRuim) {
+    int serial = 0;
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT;
+    cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK;
+    cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>) {11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>) {};
+
+    // Create a CdmaSmsMessage
+    CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData = (std::vector<uint8_t>)
+        {15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    // Create a CdmaSmsWriteArgs
+    CdmaSmsWriteArgs cdmaSmsWriteArgs;
+    cdmaSmsWriteArgs.status = CdmaSmsWriteArgsStatus::REC_UNREAD;
+    cdmaSmsWriteArgs.message = cdmaSmsMessage;
+
+    radio->writeSmsToRuim(++serial, cdmaSmsWriteArgs);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        // TODO(shuoq): radioRsp->writeSmsToRuimIndex needs to be investigated when sim card is in
+    }
+}
+
+/*
+ * Test IRadio.deleteSmsOnRuim() for the response returned.
+ */
+TEST_F(RadioHidlTest, deleteSmsOnRuim) {
+    int serial = 0;
+    int index = 1;
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT;
+    cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK;
+    cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>) {11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>) {};
+
+    // Create a CdmaSmsMessage
+    CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData = (std::vector<uint8_t>)
+        {15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    // Create a CdmaSmsWriteArgs
+    CdmaSmsWriteArgs cdmaSmsWriteArgs;
+    cdmaSmsWriteArgs.status = CdmaSmsWriteArgsStatus::REC_UNREAD;
+    cdmaSmsWriteArgs.message = cdmaSmsMessage;
+
+    radio->deleteSmsOnRuim(++serial, index);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        // TODO(shuoq): Will test right behavior when inserted sim card is considered
+    }
+}
+
+/*
+ * Test IRadio.reportSmsMemoryStatus() for the response returned.
+ */
+TEST_F(RadioHidlTest, reportSmsMemoryStatus) {
+    int serial = 0;
+    bool available = true;
+
+    radio->reportSmsMemoryStatus(++serial, available);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        // TODO(shuoq): Will add error check when we know the expected error from QC
+    } else {
+        EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error);
+    }
+}
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_utils.h b/radio/1.0/vts/functional/radio_hidl_hal_utils.h
index 0429226..329f0b4 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_utils.h
+++ b/radio/1.0/vts/functional/radio_hidl_hal_utils.h
@@ -87,6 +87,12 @@
     IccIoResult iccIoResult;
     int channelId;
 
+    // Sms
+    SendSmsResult sendSmsResult;
+    hidl_string smscAddress;
+    uint32_t writeSmsToSimIndex;
+    uint32_t writeSmsToRuimIndex;
+
     RadioResponse(RadioHidlTest& parent);
 
     virtual ~RadioResponse() = default;
@@ -234,8 +240,6 @@
     Return<void> sendOemRilRequestStringsResponse(const RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
 
-    Return<void> sendScreenStateResponse(const RadioResponseInfo& info);
-
     Return<void> setSuppServiceNotificationsResponse(
             const RadioResponseInfo& info);
 
diff --git a/radio/1.0/vts/functional/radio_response.cpp b/radio/1.0/vts/functional/radio_response.cpp
index 2b4f10f..19199ea 100644
--- a/radio/1.0/vts/functional/radio_response.cpp
+++ b/radio/1.0/vts/functional/radio_response.cpp
@@ -158,13 +158,19 @@
     return Void();
 }
 
-Return<void> RadioResponse::sendSmsResponse(const RadioResponseInfo& /*info*/,
-        const SendSmsResult& /*sms*/) {
+Return<void> RadioResponse::sendSmsResponse(const RadioResponseInfo& info,
+        const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent.notify();
     return Void();
 }
 
 Return<void> RadioResponse::sendSMSExpectMoreResponse(
-        const RadioResponseInfo& /*info*/, const SendSmsResult& /*sms*/) {
+        const RadioResponseInfo& info, const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent.notify();
     return Void();
 }
 
@@ -217,7 +223,9 @@
     return Void();
 }
 
-Return<void> RadioResponse::acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse::acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent.notify();
     return Void();
 }
 
@@ -314,23 +322,23 @@
     return Void();
 }
 
-Return<void> RadioResponse::sendScreenStateResponse(
-        const RadioResponseInfo& /*info*/) {
-    return Void();
-}
-
 Return<void> RadioResponse::setSuppServiceNotificationsResponse(
         const RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse::writeSmsToSimResponse(
-        const RadioResponseInfo& /*info*/, int32_t /*index*/) {
+        const RadioResponseInfo& info, int32_t index) {
+    rspInfo = info;
+    writeSmsToSimIndex = index;
+    parent.notify();
     return Void();
 }
 
 Return<void> RadioResponse::deleteSmsOnSimResponse(
-        const RadioResponseInfo& /*info*/) {
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent.notify();
     return Void();
 }
 
@@ -422,12 +430,17 @@
 }
 
 Return<void> RadioResponse::sendCdmaSmsResponse(
-        const RadioResponseInfo& /*info*/, const SendSmsResult& /*sms*/) {
+        const RadioResponseInfo& info, const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent.notify();
     return Void();
 }
 
 Return<void> RadioResponse::acknowledgeLastIncomingCdmaSmsResponse(
-        const RadioResponseInfo& /*info*/) {
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent.notify();
     return Void();
 }
 
@@ -469,12 +482,17 @@
 }
 
 Return<void> RadioResponse::writeSmsToRuimResponse(
-        const RadioResponseInfo& /*info*/, uint32_t /*index*/) {
+        const RadioResponseInfo& info, uint32_t index) {
+    rspInfo = info;
+    writeSmsToRuimIndex = index;
+    parent.notify();
     return Void();
 }
 
 Return<void> RadioResponse::deleteSmsOnRuimResponse(
-        const RadioResponseInfo& /*info*/) {
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent.notify();
     return Void();
 }
 
@@ -491,15 +509,22 @@
 }
 
 Return<void> RadioResponse::getSmscAddressResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) {
+        const RadioResponseInfo& info, const ::android::hardware::hidl_string& smsc) {
+    rspInfo = info;
+    smscAddress = smsc;
+    parent.notify();
     return Void();
 }
 
-Return<void> RadioResponse::setSmscAddressResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse::setSmscAddressResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent.notify();
     return Void();
 }
 
-Return<void> RadioResponse::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse::reportSmsMemoryStatusResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent.notify();
     return Void();
 }
 
@@ -518,7 +543,9 @@
 }
 
 Return<void> RadioResponse::acknowledgeIncomingGsmSmsWithPduResponse(
-        const RadioResponseInfo& /*info*/) {
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent.notify();
     return Void();
 }
 
@@ -553,7 +580,10 @@
 }
 
 Return<void> RadioResponse::sendImsSmsResponse(
-        const RadioResponseInfo& /*info*/, const SendSmsResult& /*sms*/) {
+        const RadioResponseInfo& info, const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent.notify();
     return Void();
 }
 
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
index 4e0d01d..8aa9285 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -20,6 +20,7 @@
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
 #include <hidl/Status.h>
+#include <stdatomic.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 #include <system/sound_trigger.h>
diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
index 41e7e69..273ee14 100644
--- a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
+++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -15,6 +15,12 @@
  */
 
 #define LOG_TAG "SoundTriggerHidlHalTest"
+#include <stdlib.h>
+#include <time.h>
+
+#include <condition_variable>
+#include <mutex>
+
 #include <android/log.h>
 #include <cutils/native_handle.h>
 
@@ -24,6 +30,8 @@
 
 #include <VtsHalHidlTargetBaseTest.h>
 
+#define SHORT_TIMEOUT_PERIOD (1)
+
 using ::android::hardware::audio::common::V2_0::AudioDevice;
 using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
 using ::android::hardware::soundtrigger::V2_0::SoundModelType;
@@ -36,43 +44,101 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
+/**
+ * Test code uses this class to wait for notification from callback.
+ */
+class Monitor {
+ public:
+  Monitor() : mCount(0) {}
+
+  /**
+   * Adds 1 to the internal counter and unblocks one of the waiting threads.
+   */
+  void notify() {
+    std::unique_lock<std::mutex> lock(mMtx);
+    mCount++;
+    mCv.notify_one();
+  }
+
+  /**
+   * Blocks until the internal counter becomes greater than 0.
+   *
+   * If notified, this method decreases the counter by 1 and returns true.
+   * If timeout, returns false.
+   */
+  bool wait(int timeoutSeconds) {
+    std::unique_lock<std::mutex> lock(mMtx);
+    auto deadline = std::chrono::system_clock::now() +
+        std::chrono::seconds(timeoutSeconds);
+    while (mCount == 0) {
+      if (mCv.wait_until(lock, deadline) == std::cv_status::timeout) {
+        return false;
+      }
+    }
+    mCount--;
+    return true;
+  }
+
+ private:
+  std::mutex mMtx;
+  std::condition_variable mCv;
+  int mCount;
+};
+
 // The main test class for Sound Trigger HIDL HAL.
 class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
  public:
   virtual void SetUp() override {
     mSoundTriggerHal = ::testing::VtsHalHidlTargetBaseTest::getService<ISoundTriggerHw>("sound_trigger.primary");
     ASSERT_NE(nullptr, mSoundTriggerHal.get());
-    mCallback = new MyCallback();
+    mCallback = new SoundTriggerHwCallback(*this);
     ASSERT_NE(nullptr, mCallback.get());
   }
 
-  class MyCallback : public ISoundTriggerHwCallback {
-      virtual Return<void> recognitionCallback(
-                  const ISoundTriggerHwCallback::RecognitionEvent& event __unused,
-                  int32_t cookie __unused) {
-          ALOGI("%s", __FUNCTION__);
-          return Void();
-      }
+  static void SetUpTestCase() {
+    srand(time(nullptr));
+  }
 
-      virtual Return<void> phraseRecognitionCallback(
-              const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
-              int32_t cookie __unused) {
-          ALOGI("%s", __FUNCTION__);
-          return Void();
-      }
+  class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
+   private:
+    SoundTriggerHidlTest& mParent;
 
-      virtual Return<void> soundModelCallback(
-              const ISoundTriggerHwCallback::ModelEvent& event __unused,
-              int32_t cookie __unused) {
-          ALOGI("%s", __FUNCTION__);
-          return Void();
-      }
+   public:
+    SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
+
+    virtual Return<void> recognitionCallback(
+        const ISoundTriggerHwCallback::RecognitionEvent& event __unused,
+        int32_t cookie __unused) {
+      ALOGI("%s", __FUNCTION__);
+      return Void();
+    }
+
+    virtual Return<void> phraseRecognitionCallback(
+        const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+        int32_t cookie __unused) {
+      ALOGI("%s", __FUNCTION__);
+      return Void();
+    }
+
+    virtual Return<void> soundModelCallback(
+        const ISoundTriggerHwCallback::ModelEvent& event,
+        int32_t cookie __unused) {
+      ALOGI("%s", __FUNCTION__);
+      mParent.lastModelEvent = event;
+      mParent.monitor.notify();
+      return Void();
+    }
   };
 
   virtual void TearDown() override {}
 
+  Monitor monitor;
+  // updated by soundModelCallback()
+  ISoundTriggerHwCallback::ModelEvent lastModelEvent;
+
+ protected:
   sp<ISoundTriggerHw> mSoundTriggerHal;
-  sp<MyCallback> mCallback;
+  sp<SoundTriggerHwCallback> mCallback;
 };
 
 // A class for test environment setup (kept since this file is a template).
@@ -137,6 +203,36 @@
 
   EXPECT_TRUE(hidlReturn.isOk());
   EXPECT_NE(0, ret);
+  EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+  int ret = -ENODEV;
+  ISoundTriggerHw::SoundModel model;
+  SoundModelHandle handle = 0;
+
+  model.type = SoundModelType::GENERIC;
+  model.data.resize(100);
+  for (auto& d : model.data) {
+    d = rand();
+  }
+
+  Return<void> loadReturn = mSoundTriggerHal->loadSoundModel(
+      model,
+      mCallback, 0, [&](int32_t retval, auto res) {
+    ret = retval;
+    handle = res;
+  });
+
+  EXPECT_TRUE(loadReturn.isOk());
+  EXPECT_NE(0, ret);
+  EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
 }
 
 /**
diff --git a/tests/Android.bp b/tests/Android.bp
index 997ba79..6606d94 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -16,6 +16,7 @@
     "memory/1.0",
     "memory/1.0/default",
     "msgq/1.0",
+    "msgq/1.0/default",
     "pointer/1.0",
     "pointer/1.0/default",
     "pointer/1.0/default/lib",
diff --git a/tests/msgq/1.0/Android.bp b/tests/msgq/1.0/Android.bp
index d17efe4..2d42699 100644
--- a/tests/msgq/1.0/Android.bp
+++ b/tests/msgq/1.0/Android.bp
@@ -3,6 +3,7 @@
 filegroup {
     name: "android.hardware.tests.msgq@1.0_hal",
     srcs: [
+        "IBenchmarkMsgQ.hal",
         "ITestMsgQ.hal",
     ],
 }
@@ -15,6 +16,7 @@
         ":android.hardware.tests.msgq@1.0_hal",
     ],
     out: [
+        "android/hardware/tests/msgq/1.0/BenchmarkMsgQAll.cpp",
         "android/hardware/tests/msgq/1.0/TestMsgQAll.cpp",
     ],
 }
@@ -27,6 +29,11 @@
         ":android.hardware.tests.msgq@1.0_hal",
     ],
     out: [
+        "android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/IHwBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/BnHwBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/BpHwBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/BsBenchmarkMsgQ.h",
         "android/hardware/tests/msgq/1.0/ITestMsgQ.h",
         "android/hardware/tests/msgq/1.0/IHwTestMsgQ.h",
         "android/hardware/tests/msgq/1.0/BnHwTestMsgQ.h",
diff --git a/benchmarks/msgq/1.0/IBenchmarkMsgQ.hal b/tests/msgq/1.0/IBenchmarkMsgQ.hal
similarity index 98%
rename from benchmarks/msgq/1.0/IBenchmarkMsgQ.hal
rename to tests/msgq/1.0/IBenchmarkMsgQ.hal
index c4b9d95..81754a4 100644
--- a/benchmarks/msgq/1.0/IBenchmarkMsgQ.hal
+++ b/tests/msgq/1.0/IBenchmarkMsgQ.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.benchmarks.msgq@1.0;
+package android.hardware.tests.msgq@1.0;
 
 interface IBenchmarkMsgQ {
     /*
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
new file mode 100644
index 0000000..b53fcd3
--- /dev/null
+++ b/tests/msgq/1.0/default/Android.bp
@@ -0,0 +1,19 @@
+cc_library_shared {
+    name: "android.hardware.tests.msgq@1.0-impl",
+    relative_install_path: "hw",
+    proprietary: true,
+    srcs: [
+        "TestMsgQ.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.tests.msgq@1.0",
+        "android.hidl.base@1.0",
+    ],
+}
diff --git a/tests/msgq/1.0/default/TestMsgQ.cpp b/tests/msgq/1.0/default/TestMsgQ.cpp
new file mode 100644
index 0000000..7cc4f5b
--- /dev/null
+++ b/tests/msgq/1.0/default/TestMsgQ.cpp
@@ -0,0 +1,135 @@
+#include "TestMsgQ.h"
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
+Return<void> TestMsgQ::configureFmqSyncReadWrite(configureFmqSyncReadWrite_cb _hidl_cb) {
+    static constexpr size_t kNumElementsInQueue = 1024;
+    mFmqSynchronized.reset(new (std::nothrow) MessageQueueSync(
+            kNumElementsInQueue, true /* configureEventFlagWord */));
+    if ((mFmqSynchronized == nullptr) || (mFmqSynchronized->isValid() == false)) {
+        _hidl_cb(false /* ret */, MessageQueueSync::Descriptor());
+    } else {
+        /*
+         * Initialize the EventFlag word with bit FMQ_NOT_FULL.
+         */
+        auto evFlagWordPtr = mFmqSynchronized->getEventFlagWord();
+        if (evFlagWordPtr != nullptr) {
+            std::atomic_init(evFlagWordPtr,
+                             static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL));
+        }
+        _hidl_cb(true /* ret */, *mFmqSynchronized->getDesc());
+    }
+    return Void();
+}
+
+Return<void> TestMsgQ::getFmqUnsyncWrite(bool configureFmq, getFmqUnsyncWrite_cb _hidl_cb) {
+    if (configureFmq) {
+        static constexpr size_t kNumElementsInQueue = 1024;
+        mFmqUnsynchronized.reset(new (std::nothrow) MessageQueueUnsync(kNumElementsInQueue));
+    }
+    if ((mFmqUnsynchronized == nullptr) ||
+        (mFmqUnsynchronized->isValid() == false)) {
+        _hidl_cb(false /* ret */, MessageQueueUnsync::Descriptor());
+    } else {
+        _hidl_cb(true /* ret */, *mFmqUnsynchronized->getDesc());
+    }
+    return Void();
+}
+
+Return<bool> TestMsgQ::requestWriteFmqSync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    for (int i = 0; i < count; i++) {
+        data[i] = i;
+    }
+    bool result = mFmqSynchronized->write(&data[0], count);
+    return result;
+}
+
+Return<bool> TestMsgQ::requestReadFmqSync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result = mFmqSynchronized->read(&data[0], count)
+            && verifyData(&data[0], count);
+    return result;
+}
+
+Return<bool> TestMsgQ::requestWriteFmqUnsync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    for (int i = 0; i < count; i++) {
+        data[i] = i;
+    }
+    bool result = mFmqUnsynchronized->write(&data[0], count);
+    return result;
+}
+
+Return<bool> TestMsgQ::requestReadFmqUnsync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result =
+            mFmqUnsynchronized->read(&data[0], count) && verifyData(&data[0], count);
+    return result;
+}
+
+Return<void> TestMsgQ::requestBlockingRead(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result = mFmqSynchronized->readBlocking(
+            &data[0],
+            count,
+            static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+            static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+            5000000000 /* timeOutNanos */);
+
+    if (result == false) {
+        ALOGE("Blocking read fails");
+    }
+    return Void();
+}
+
+Return<void> TestMsgQ::requestBlockingReadDefaultEventFlagBits(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result = mFmqSynchronized->readBlocking(
+            &data[0],
+            count);
+
+    if (result == false) {
+        ALOGE("Blocking read fails");
+    }
+
+    return Void();
+}
+
+Return<void> TestMsgQ::requestBlockingReadRepeat(int32_t count, int32_t numIter) {
+    std::vector<uint16_t> data(count);
+    for (int i = 0; i < numIter; i++) {
+        bool result = mFmqSynchronized->readBlocking(
+                &data[0],
+                count,
+                static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+                static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+                5000000000 /* timeOutNanos */);
+
+        if (result == false) {
+            ALOGE("Blocking read fails");
+            break;
+        }
+    }
+    return Void();
+}
+
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+ITestMsgQ* HIDL_FETCH_ITestMsgQ(const char* /* name */) {
+    return new TestMsgQ();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace msgq
+}  // namespace tests
+}  // namespace hardware
+}  // namespace android
diff --git a/tests/msgq/1.0/default/TestMsgQ.h b/tests/msgq/1.0/default/TestMsgQ.h
new file mode 100644
index 0000000..760d931
--- /dev/null
+++ b/tests/msgq/1.0/default/TestMsgQ.h
@@ -0,0 +1,77 @@
+#ifndef ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
+#define ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
+
+#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/MessageQueue.h>
+#include <fmq/EventFlag.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tests::msgq::V1_0::ITestMsgQ;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
+using android::hardware::MQDescriptorSync;
+using android::hardware::MQDescriptorUnsync;
+
+using android::hardware::MessageQueue;
+
+struct TestMsgQ : public ITestMsgQ {
+    typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync;
+    typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync;
+
+    TestMsgQ() : mFmqSynchronized(nullptr), mFmqUnsynchronized(nullptr) {}
+
+    // Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
+    Return<void> configureFmqSyncReadWrite(configureFmqSyncReadWrite_cb _hidl_cb) override;
+    Return<void> getFmqUnsyncWrite(bool configureFmq, getFmqUnsyncWrite_cb _hidl_cb) override;
+    Return<bool> requestWriteFmqSync(int32_t count) override;
+    Return<bool> requestReadFmqSync(int32_t count) override;
+    Return<bool> requestWriteFmqUnsync(int32_t count) override;
+    Return<bool> requestReadFmqUnsync(int32_t count) override;
+    Return<void> requestBlockingRead(int32_t count) override;
+    Return<void> requestBlockingReadDefaultEventFlagBits(int32_t count) override;
+    Return<void> requestBlockingReadRepeat(int32_t count, int32_t numIter) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+private:
+    std::unique_ptr<MessageQueueSync> mFmqSynchronized;
+    std::unique_ptr<MessageQueueUnsync> mFmqUnsynchronized;
+
+    /*
+     * Utility function to verify data read from the fast message queue.
+     */
+    bool verifyData(uint16_t* data, int count) {
+        for (int i = 0; i < count; i++) {
+            if (data[i] != i) return false;
+        }
+        return true;
+    }
+};
+
+extern "C" ITestMsgQ* HIDL_FETCH_ITestMsgQ(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace msgq
+}  // namespace tests
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
diff --git a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
index c0ae4d4..696b1f9 100644
--- a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
@@ -1,4 +1,4 @@
 service wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
     class hal
     user wifi
-    group wifi
+    group wifi gps
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index 82364cb..5917efc 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -96,7 +96,7 @@
   if (!hidl_caps) {
     return false;
   }
-  *hidl_caps = 0;
+  *hidl_caps = {};
   using HidlChipCaps = IWifiChip::ChipCapabilityMask;
   for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
                              legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
@@ -133,6 +133,7 @@
   if (!hidl_status) {
     return false;
   }
+  *hidl_status = {};
   hidl_status->ringName = reinterpret_cast<const char*>(legacy_status.name);
   hidl_status->flags = 0;
   for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
@@ -165,7 +166,7 @@
   if (!hidl_status_vec) {
     return false;
   }
-  hidl_status_vec->clear();
+  *hidl_status_vec = {};
   for (const auto& legacy_status : legacy_status_vec) {
     WifiDebugRingBufferStatus hidl_status;
     if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
@@ -183,6 +184,7 @@
   if (!hidl_stats) {
     return false;
   }
+  *hidl_stats = {};
   hidl_stats->totalCmdEventWakeCnt =
       legacy_stats.wake_reason_cnt.total_cmd_event_wake;
   hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
@@ -227,6 +229,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   *hidl_caps = 0;
   using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
   for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
@@ -263,6 +266,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   hidl_caps->version = legacy_caps.version;
   hidl_caps->maxLength = legacy_caps.max_len;
   return true;
@@ -299,6 +303,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
   hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
   hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
@@ -332,6 +337,7 @@
   if (!legacy_scan_params) {
     return false;
   }
+  *legacy_scan_params = {};
   legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
   legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
   legacy_scan_params->report_threshold_percent =
@@ -348,9 +354,12 @@
         hidl_scan_params.buckets[bucket_idx];
     legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
         legacy_scan_params->buckets[bucket_idx];
-    legacy_bucket_spec.bucket = bucket_idx;
+    if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+      return false;
+    }
+    legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
     legacy_bucket_spec.band =
-        static_cast<legacy_hal::wifi_band>(hidl_bucket_spec.band);
+        convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
     legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
     legacy_bucket_spec.max_period = hidl_bucket_spec.exponentialMaxPeriodInMs;
     legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
@@ -384,6 +393,7 @@
   if (!hidl_ie) {
     return false;
   }
+  *hidl_ie = {};
   hidl_ie->id = legacy_ie.id;
   hidl_ie->data =
       std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
@@ -396,6 +406,7 @@
   if (!ie_blob || !hidl_ies) {
     return false;
   }
+  *hidl_ies = {};
   const uint8_t* ies_begin = ie_blob;
   const uint8_t* ies_end = ie_blob + ie_blob_len;
   const uint8_t* next_ie = ies_begin;
@@ -426,10 +437,11 @@
   if (!hidl_scan_result) {
     return false;
   }
+  *hidl_scan_result = {};
   hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
   hidl_scan_result->ssid = std::vector<uint8_t>(
       legacy_scan_result.ssid,
-      legacy_scan_result.ssid + sizeof(legacy_scan_result.ssid));
+      legacy_scan_result.ssid + strlen(legacy_scan_result.ssid));
   memcpy(hidl_scan_result->bssid.data(),
          legacy_scan_result.bssid,
          hidl_scan_result->bssid.size());
@@ -456,6 +468,7 @@
   if (!hidl_scan_data) {
     return false;
   }
+  *hidl_scan_data = {};
   hidl_scan_data->flags = 0;
   for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
     if (legacy_cached_scan_result.flags & flag) {
@@ -492,7 +505,7 @@
   if (!hidl_scan_datas) {
     return false;
   }
-  hidl_scan_datas->clear();
+  *hidl_scan_datas = {};
   for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
     StaScanData hidl_scan_data;
     if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
@@ -579,6 +592,7 @@
   if (!hidl_frame) {
     return false;
   }
+  *hidl_frame = {};
   hidl_frame->frameType =
       convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
   hidl_frame->frameLen = legacy_frame.frame_len;
@@ -597,6 +611,7 @@
   if (!hidl_fate) {
     return false;
   }
+  *hidl_fate = {};
   hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
   return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
                                                  &hidl_fate->frameInfo);
@@ -608,7 +623,7 @@
   if (!hidl_fates) {
     return false;
   }
-  hidl_fates->clear();
+  *hidl_fates = {};
   for (const auto& legacy_fate : legacy_fates) {
     WifiDebugTxPacketFateReport hidl_fate;
     if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
@@ -625,6 +640,7 @@
   if (!hidl_fate) {
     return false;
   }
+  *hidl_fate = {};
   hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
   return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
                                                  &hidl_fate->frameInfo);
@@ -636,7 +652,7 @@
   if (!hidl_fates) {
     return false;
   }
-  hidl_fates->clear();
+  *hidl_fates = {};
   for (const auto& legacy_fate : legacy_fates) {
     WifiDebugRxPacketFateReport hidl_fate;
     if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
@@ -653,6 +669,7 @@
   if (!hidl_stats) {
     return false;
   }
+  *hidl_stats = {};
   // iface legacy_stats conversion.
   hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
   hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
@@ -706,6 +723,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
   hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
   return true;
@@ -717,6 +735,7 @@
   if (!legacy_config) {
     return false;
   }
+  *legacy_config = {};
   if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
       hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
     return false;
@@ -762,7 +781,7 @@
     LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: null legacy_request";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanEnableRequest));
+  *legacy_request = {};
 
   legacy_request->config_2dot4g_support = 1;
   legacy_request->support_2dot4g_val = hidl_request.operateInBand[
@@ -892,7 +911,7 @@
     LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: null legacy_request";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanPublishRequest));
+  *legacy_request = {};
 
   legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
   legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
@@ -984,7 +1003,7 @@
     LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanSubscribeRequest));
+  *legacy_request = {};
 
   legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
   legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
@@ -1089,7 +1108,7 @@
     LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanTransmitFollowupRequest));
+  *legacy_request = {};
 
   legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
   legacy_request->requestor_instance_id = hidl_request.peerId;
@@ -1128,7 +1147,7 @@
     LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanConfigRequest));
+  *legacy_request = {};
 
   // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown defaults
   legacy_request->master_pref = hidl_request.masterPref;
@@ -1218,7 +1237,7 @@
     LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanDataPathInitiatorRequest));
+  *legacy_request = {};
 
   legacy_request->requestor_instance_id = hidl_request.peerId;
   memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
@@ -1253,7 +1272,7 @@
     LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanDataPathIndicationResponse));
+  *legacy_request = {};
 
   legacy_request->rsp_code = hidl_request.acceptRequest ?
         legacy_hal::NAN_DP_REQUEST_ACCEPT : legacy_hal::NAN_DP_REQUEST_REJECT;
@@ -1286,9 +1305,10 @@
     LOG(ERROR) << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
     return false;
   }
+  *wifiNanStatus = {};
+
   wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(legacy_response.status);
   wifiNanStatus->description = legacy_response.nan_error;
-
   return true;
 }
 
@@ -1299,6 +1319,8 @@
     LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: hidl_response is null";
     return false;
   }
+  *hidl_response = {};
+
   hidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters;
   hidl_response->maxPublishes = legacy_response.max_publishes;
   hidl_response->maxSubscribes = legacy_response.max_subscribes;
@@ -1325,6 +1347,8 @@
     LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
   hidl_ind->peerId = legacy_ind.requestor_instance_id;
   hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
@@ -1356,6 +1380,8 @@
     LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
   hidl_ind->peerId = legacy_ind.requestor_instance_id;
   hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
@@ -1376,6 +1402,8 @@
     LOG(ERROR) << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
   hidl_ind->peerDiscMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
   hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
@@ -1394,6 +1422,8 @@
     LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
   hidl_ind->dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
   hidl_ind->peerNdiMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
@@ -1635,6 +1665,7 @@
   if (!legacy_info) {
     return false;
   }
+  *legacy_info = {};
   legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
   legacy_info->center_freq = hidl_info.centerFreq;
   legacy_info->center_freq0 = hidl_info.centerFreq0;
@@ -1648,6 +1679,7 @@
   if (!hidl_info) {
     return false;
   }
+  *hidl_info = {};
   hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
   hidl_info->centerFreq = legacy_info.center_freq;
   hidl_info->centerFreq0 = legacy_info.center_freq0;
@@ -1660,6 +1692,7 @@
   if (!legacy_config) {
     return false;
   }
+  *legacy_config = {};
   CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
   memcpy(legacy_config->addr, hidl_config.addr.data(), hidl_config.addr.size());
   legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
@@ -1688,7 +1721,7 @@
   if (!legacy_configs) {
     return false;
   }
-  legacy_configs->clear();
+  *legacy_configs = {};
   for (const auto& hidl_config : hidl_configs) {
     legacy_hal::wifi_rtt_config legacy_config;
     if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
@@ -1705,6 +1738,7 @@
   if (!legacy_info) {
     return false;
   }
+  *legacy_info = {};
   legacy_info->latitude = hidl_info.latitude;
   legacy_info->longitude = hidl_info.longitude;
   legacy_info->altitude = hidl_info.altitude;
@@ -1725,6 +1759,7 @@
   if (!legacy_info) {
     return false;
   }
+  *legacy_info = {};
   CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
   memcpy(legacy_info->country_code,
          hidl_info.countryCode.data(),
@@ -1745,6 +1780,7 @@
   if (!legacy_responder) {
     return false;
   }
+  *legacy_responder = {};
   if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
                                           &legacy_responder->channel)) {
     return false;
@@ -1760,6 +1796,7 @@
   if (!hidl_responder) {
     return false;
   }
+  *hidl_responder = {};
   if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
                                           &hidl_responder->channel)) {
     return false;
@@ -1775,6 +1812,7 @@
   if (!hidl_capabilities) {
     return false;
   }
+  *hidl_capabilities = {};
   hidl_capabilities->rttOneSidedSupported =
       legacy_capabilities.rtt_one_sided_supported;
   hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
@@ -1814,6 +1852,7 @@
   if (!hidl_rate) {
     return false;
   }
+  *hidl_rate = {};
   hidl_rate->preamble =
       convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
   hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
@@ -1829,6 +1868,7 @@
   if (!hidl_result) {
     return false;
   }
+  *hidl_result = {};
   CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
   memcpy(
       hidl_result->addr.data(), legacy_result.addr, sizeof(legacy_result.addr));
@@ -1873,7 +1913,7 @@
   if (!hidl_results) {
     return false;
   }
-  hidl_results->clear();
+  *hidl_results = {};
   for (const auto legacy_result : legacy_results) {
     RttResult hidl_result;
     if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.0/default/wifi.cpp
index 3d482b4..b48844e 100644
--- a/wifi/1.0/default/wifi.cpp
+++ b/wifi/1.0/default/wifi.cpp
@@ -115,6 +115,7 @@
       }
     }
   }
+  LOG(INFO) << "Wifi HAL started";
   return wifi_status;
 }
 
@@ -139,6 +140,13 @@
       }
     }
   }
+  // Clear the chip object and its child objects since the HAL is now
+  // stopped.
+  if (chip_.get()) {
+    chip_->invalidate();
+    chip_.clear();
+  }
+  LOG(INFO) << "Wifi HAL stopped";
   return wifi_status;
 }
 
@@ -172,13 +180,7 @@
 
 WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController() {
   run_state_ = RunState::STOPPING;
-  const auto on_complete_callback_ = [&]() {
-    if (chip_.get()) {
-      chip_->invalidate();
-    }
-    chip_.clear();
-    run_state_ = RunState::STOPPED;
-  };
+  const auto on_complete_callback_ = [&]() { run_state_ = RunState::STOPPED; };
   legacy_hal::wifi_error legacy_status =
       legacy_hal_->stop(on_complete_callback_);
   if (legacy_status != legacy_hal::WIFI_SUCCESS) {
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index 83e6660..d90d5be 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -320,6 +320,11 @@
  */
 struct StaBackgroundScanBucketParameters {
   /**
+   * Bucket index. This index is used to report results in
+   * |StaScanData.bucketsScanned|.
+   */
+  uint32_t bucketIdx;
+  /**
    * Bands to scan or |BAND_UNSPECIFIED| if frequencies list must be used
    * instead.
    */
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 9042075..e0c92fe 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -36,11 +36,12 @@
 using ::android::hardware::hidl_vec;
 
 void stopFramework() {
-    ASSERT_EQ(std::system("svc wifi disable"), 0);
+    ASSERT_EQ(std::system("stop"), 0);
+    stopWifi();
     sleep(5);
 }
 
-void startFramework() { ASSERT_EQ(std::system("svc wifi enable"), 0); }
+void startFramework() { ASSERT_EQ(std::system("start"), 0); }
 
 sp<IWifi> getWifi() {
     sp<IWifi> wifi = ::testing::VtsHalHidlTargetBaseTest::getService<IWifi>();
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index eb482c9..95c0e5d 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -17,24 +17,427 @@
 #include <android-base/logging.h>
 
 #include <android/hardware/wifi/1.0/IWifiNanIface.h>
+#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
 
 #include <VtsHalHidlTargetBaseTest.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
 
+#include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
 
-using ::android::hardware::wifi::V1_0::IWifiNanIface;
+using namespace ::android::hardware::wifi::V1_0;
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
 using ::android::sp;
 
+#define TIMEOUT_PERIOD 10
+
 /**
  * Fixture to use for all NAN Iface HIDL interface tests.
  */
 class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
-   public:
-    virtual void SetUp() override {}
+  public:
+    virtual void SetUp() override {
+      iwifiNanIface = getWifiNanIface();
+      ASSERT_NE(nullptr, iwifiNanIface.get());
+      ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback,
+            new WifiNanIfaceEventCallback(*this)).code);
+    }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override {
+      stopWifi();
+    }
 
-   protected:
+    /* Used as a mechanism to inform the test about data/event callback */
+    inline void notify() {
+      std::unique_lock<std::mutex> lock(mtx_);
+      count_++;
+      cv_.notify_one();
+    }
+
+    enum CallbackType {
+        INVALID = -2,
+        ANY_CALLBACK = -1,
+
+        NOTIFY_CAPABILITIES_RESPONSE = 0,
+        NOTIFY_ENABLE_RESPONSE,
+        NOTIFY_CONFIG_RESPONSE,
+        NOTIFY_DISABLE_RESPONSE,
+        NOTIFY_START_PUBLISH_RESPONSE,
+        NOTIFY_STOP_PUBLISH_RESPONSE,
+        NOTIFY_START_SUBSCRIBE_RESPONSE,
+        NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+        NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+        NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+        NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+        NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+
+        EVENT_CLUSTER_EVENT,
+        EVENT_DISABLED,
+        EVENT_PUBLISH_TERMINATED,
+        EVENT_SUBSCRIBE_TERMINATED,
+        EVENT_MATCH,
+        EVENT_MATCH_EXPIRED,
+        EVENT_FOLLOWUP_RECEIVED,
+        EVENT_TRANSMIT_FOLLOWUP,
+        EVENT_DATA_PATH_REQUEST,
+        EVENT_DATA_PATH_CONFIRM,
+        EVENT_DATA_PATH_TERMINATED
+    };
+
+    /* Test code calls this function to wait for data/event callback */
+    inline std::cv_status wait(CallbackType waitForCallbackType) {
+      std::unique_lock<std::mutex> lock(mtx_);
+
+      EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a non-void-returning method
+
+      callbackType = INVALID;
+      std::cv_status status = std::cv_status::no_timeout;
+      auto now = std::chrono::system_clock::now();
+      while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) return status;
+        if (waitForCallbackType != ANY_CALLBACK && callbackType != INVALID
+            && callbackType != waitForCallbackType) {
+          count_--;
+        }
+      }
+      count_--;
+      return status;
+    }
+
+    class WifiNanIfaceEventCallback: public IWifiNanIfaceEventCallback {
+      WifiNanIfaceHidlTest& parent_;
+
+     public:
+      WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent) : parent_(parent) {};
+
+      virtual ~WifiNanIfaceEventCallback() = default;
+
+      Return<void> notifyCapabilitiesResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            const NanCapabilities& capabilities) override {
+        parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.capabilities = capabilities;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyEnableResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_ENABLE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyConfigResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_CONFIG_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyDisableResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_DISABLE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStartPublishResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            uint8_t sessionId) override {
+        parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.sessionId = sessionId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStopPublishResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStartSubscribeResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            uint8_t sessionId) override {
+        parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.sessionId = sessionId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStopSubscribeResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyTransmitFollowupResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyCreateDataInterfaceResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyDeleteDataInterfaceResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyInitiateDataPathResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            uint32_t ndpInstanceId) override {
+        parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.ndpInstanceId = ndpInstanceId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyRespondToDataPathIndicationResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyTerminateDataPathResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventClusterEvent(
+            const NanClusterEventInd& event) override {
+        parent_.callbackType = EVENT_CLUSTER_EVENT;
+
+        parent_.nanClusterEventInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDisabled(
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_DISABLED;
+
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventPublishTerminated(
+            uint8_t sessionId,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_PUBLISH_TERMINATED;
+
+        parent_.sessionId = sessionId;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventSubscribeTerminated(
+            uint8_t sessionId,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED;
+
+        parent_.sessionId = sessionId;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventMatch(
+            const NanMatchInd& event) override {
+        parent_.callbackType = EVENT_MATCH;
+
+        parent_.nanMatchInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventMatchExpired(
+            uint8_t discoverySessionId,
+            uint32_t peerId) override {
+        parent_.callbackType = EVENT_MATCH_EXPIRED;
+
+        parent_.sessionId = discoverySessionId;
+        parent_.peerId = peerId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventFollowupReceived(
+            const NanFollowupReceivedInd& event) override {
+        parent_.callbackType = EVENT_FOLLOWUP_RECEIVED;
+
+        parent_.nanFollowupReceivedInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventTransmitFollowup(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDataPathRequest(
+            const NanDataPathRequestInd& event) override {
+        parent_.callbackType = EVENT_DATA_PATH_REQUEST;
+
+        parent_.nanDataPathRequestInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDataPathConfirm(
+            const NanDataPathConfirmInd& event) override {
+        parent_.callbackType = EVENT_DATA_PATH_CONFIRM;
+
+        parent_.nanDataPathConfirmInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDataPathTerminated(
+            uint32_t ndpInstanceId) override {
+        parent_.callbackType = EVENT_DATA_PATH_TERMINATED;
+
+        parent_.ndpInstanceId = ndpInstanceId;
+
+        parent_.notify();
+        return Void();
+      }
+    };
+
+    private:
+      // synchronization objects
+      std::mutex mtx_;
+      std::condition_variable cv_;
+      int count_;
+
+    protected:
+      android::sp<IWifiNanIface> iwifiNanIface;
+
+      // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of all
+      // arguments to all callbacks. They are set by the callback (notifications or
+      // events) and can be retrieved by tests.
+      CallbackType callbackType;
+      uint16_t id;
+      WifiNanStatus status;
+      NanCapabilities capabilities;
+      uint8_t sessionId;
+      uint32_t ndpInstanceId;
+      NanClusterEventInd nanClusterEventInd;
+      NanMatchInd nanMatchInd;
+      uint32_t peerId;
+      NanFollowupReceivedInd nanFollowupReceivedInd;
+      NanDataPathRequestInd nanDataPathRequestInd;
+      NanDataPathConfirmInd nanDataPathConfirmInd;
 };
 
 /*
@@ -43,6 +446,49 @@
  * successfully created.
  */
 TEST(WifiNanIfaceHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiNanIface().get());
-    stopWifi();
+  ASSERT_NE(nullptr, getWifiNanIface().get());
+  stopWifi();
+}
+
+/*
+ * Fail: use past destruction
+ * Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi
+ * is disabled.
+ */
+TEST(WifiNanIfaceHidlTestNoFixture, FailOnIfaceInvalid) {
+  android::sp<IWifiNanIface> iwifiNanIface = getWifiNanIface();
+  ASSERT_NE(nullptr, iwifiNanIface.get());
+  stopWifi();
+  sleep(5); // make sure that all chips/interfaces are invalidated
+  ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+          HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
+}
+
+/*
+ * getCapabilitiesRequest: validate that returns capabilities.
+ */
+TEST_F(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
+  uint16_t inputCmdId = 10;
+  ASSERT_EQ(WifiStatusCode::SUCCESS,
+        HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code);
+  // wait for a callback
+  ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
+  ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
+  ASSERT_EQ(id, inputCmdId);
+
+  // check for reasonable capability values
+  EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxPublishes, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxSubscribes, (unsigned int) 0);
+  EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int) 255);
+  EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int) 255);
+  EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int) 255);
+  EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int) 255);
+  EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int) 255);
+  EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxNdpSessions, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int) 0);
+  EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int) 0);
 }
diff --git a/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
index dd1d1c4..2223022 100644
--- a/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
@@ -278,8 +278,10 @@
    *        reject.
    * @param statusCode 802.11 code to indicate the reject reason.
    *        Refer to section 8.4.1.9 of IEEE 802.11 spec.
+   * @param timedOut Whether failure is due to timeout rather
+   *        than explicit rejection response from the AP.
    */
-  oneway onAssociationRejected(Bssid bssid, uint32_t statusCode);
+  oneway onAssociationRejected(Bssid bssid, uint32_t statusCode, bool timedOut);
 
   /**
    * Used to indicate the timeout of authentication to an AP.
diff --git a/wifi/supplicant/1.0/ISupplicantStaNetwork.hal b/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
index 37e8d3f..7d5159a 100644
--- a/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
@@ -277,6 +277,20 @@
   setPskPassphrase(string psk) generates (SupplicantStatus status);
 
   /**
+   * Set raw psk for WPA_PSK network.
+   *
+   * @param psk value to set as specified in IEEE 802.11i-2004 standard.
+   *        This is the calculated using 'wpa_passphrase <ssid> [passphrase]'
+   * @return status Status of the operation.
+   *         Possible status codes:
+   *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+   *         |SupplicantStatusCode.SUCCESS|,
+   *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+   *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+   */
+  setPsk(uint8_t[32] psk) generates (SupplicantStatus status);
+
+  /**
    * Set WEP key for WEP network.
    *
    * @param keyIdx Index of wep key to set.
@@ -662,6 +676,8 @@
 
   /**
    * Get passphrase for WPA_PSK network.
+   * Must return a failure if network has no passphrase set (use |getPsk| if
+   * network was configured with raw psk instead).
    *
    * @return status Status of the operation.
    *         Possible status codes:
@@ -672,6 +688,19 @@
   getPskPassphrase() generates (SupplicantStatus status, string psk);
 
   /**
+   * Get raw psk for WPA_PSK network.
+   *
+   * @return status Status of the operation.
+   *         Possible status codes:
+   *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+   *         |SupplicantStatusCode.SUCCESS|,
+   *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+   *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+   * @param psk value set.
+   */
+  getPsk() generates (SupplicantStatus status, uint8_t[32] psk);
+
+  /**
    * Get WEP key for WEP network.
    *
    * @param keyIdx Index of wep key to be fetched.