Merge "Avoid injected location fused in GNSS location"
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
index 520e776..122c550 100644
--- a/audio/6.0/IDevice.hal
+++ b/audio/6.0/IDevice.hal
@@ -286,8 +286,12 @@
      * all currently allocated resources. It is recommended to close
      * the device on the client side as soon as it is becomes unused.
      *
+     * Note that all streams must be closed by the client before
+     * attempting to close the device they belong to.
+     *
      * @return retval OK in case the success.
-     *                INVALID_STATE if the device was already closed.
+     *                INVALID_STATE if the device was already closed
+     *                or there are streams currently opened.
      */
     @exit
     close() generates (Result retval);
diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp
index 11872c0..eddff55 100644
--- a/audio/core/all-versions/default/Conversions.cpp
+++ b/audio/core/all-versions/default/Conversions.cpp
@@ -19,6 +19,7 @@
 #include <stdio.h>
 
 #include <log/log.h>
+#include <media/AudioContainers.h>
 
 namespace android {
 namespace hardware {
@@ -31,26 +32,22 @@
     char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
     memset(halAddress, 0, sizeof(halAddress));
     uint32_t halDevice = static_cast<uint32_t>(address.device);
-    const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
-        (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+    if (getAudioDeviceOutAllA2dpSet().count(halDevice) > 0 ||
+        halDevice == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
         snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
                  address.address.mac[0], address.address.mac[1], address.address.mac[2],
                  address.address.mac[3], address.address.mac[4], address.address.mac[5]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_IP || halDevice == AUDIO_DEVICE_IN_IP) {
         snprintf(halAddress, sizeof(halAddress), "%d.%d.%d.%d", address.address.ipv4[0],
                  address.address.ipv4[1], address.address.ipv4[2], address.address.ipv4[3]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) {
+    } else if (getAudioDeviceOutAllUsbSet().count(halDevice) > 0 ||
+               getAudioDeviceInAllUsbSet().count(halDevice) > 0) {
         snprintf(halAddress, sizeof(halAddress), "card=%d;device=%d", address.address.alsa.card,
                  address.address.alsa.device);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_BUS || halDevice == AUDIO_DEVICE_IN_BUS) {
         snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str());
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+               halDevice == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
         snprintf(halAddress, sizeof(halAddress), "%s", address.rSubmixAddress.c_str());
     }
     return halAddress;
@@ -67,32 +64,28 @@
         return OK;
     }
 
-    const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) device &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
-        (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+    if (getAudioDeviceOutAllA2dpSet().count(device) > 0 ||
+        device == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
         int status =
             sscanf(halAddress, "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &address->address.mac[0],
                    &address->address.mac[1], &address->address.mac[2], &address->address.mac[3],
                    &address->address.mac[4], &address->address.mac[5]);
         return status == 6 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0) ||
-               (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) {
+    } else if (device == AUDIO_DEVICE_OUT_IP || device == AUDIO_DEVICE_IN_IP) {
         int status =
             sscanf(halAddress, "%hhu.%hhu.%hhu.%hhu", &address->address.ipv4[0],
                    &address->address.ipv4[1], &address->address.ipv4[2], &address->address.ipv4[3]);
         return status == 4 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0 ||
-               (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) {
+    } else if (getAudioDeviceOutAllUsbSet().count(device) > 0 ||
+               getAudioDeviceInAllUsbSet().count(device) > 0) {
         int status = sscanf(halAddress, "card=%d;device=%d", &address->address.alsa.card,
                             &address->address.alsa.device);
         return status == 2 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0) ||
-               (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) {
+    } else if (device == AUDIO_DEVICE_OUT_BUS || device == AUDIO_DEVICE_IN_BUS) {
         address->busAddress = halAddress;
         return OK;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
-               (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+    } else if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+               device == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
         address->rSubmixAddress = halAddress;
         return OK;
     }
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 5ea4c8d..21dab00 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -53,10 +53,14 @@
 
 void Device::closeInputStream(audio_stream_in_t* stream) {
     mDevice->close_input_stream(mDevice, stream);
+    LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
+    --mOpenedStreamsCount;
 }
 
 void Device::closeOutputStream(audio_stream_out_t* stream) {
     mDevice->close_output_stream(mDevice, stream);
+    LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
+    --mOpenedStreamsCount;
 }
 
 char* Device::halGetParameters(const char* keys) {
@@ -158,6 +162,7 @@
     sp<IStreamOut> streamOut;
     if (status == OK) {
         streamOut = new StreamOut(this, halStream);
+        ++mOpenedStreamsCount;
     }
     HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
     return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut};
@@ -184,6 +189,7 @@
     sp<IStreamIn> streamIn;
     if (status == OK) {
         streamIn = new StreamIn(this, halStream);
+        ++mOpenedStreamsCount;
     }
     HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
     return {analyzeStatus("open_input_stream", status, {EINVAL} /*ignore*/), streamIn};
@@ -383,7 +389,7 @@
 #endif
 
 Result Device::doClose() {
-    if (mIsClosed) return Result::INVALID_STATE;
+    if (mIsClosed || mOpenedStreamsCount != 0) return Result::INVALID_STATE;
     mIsClosed = true;
     return analyzeStatus("close", audio_hw_device_close(mDevice));
 }
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index dc53a39..11ab607 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -130,6 +130,7 @@
   private:
     bool mIsClosed;
     audio_hw_device_t* mDevice;
+    int mOpenedStreamsCount = 0;
 
     virtual ~Device();
 
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 81f963d..709b7cd 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -52,7 +52,6 @@
         doc::test(
             "Make sure getMicrophones always succeeds"
             "and getActiveMicrophones always succeeds when recording from these microphones.");
-        AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
         AudioConfig config{};
         config.channelMask = mkEnumBitfield(AudioChannelMask::IN_MONO);
         config.sampleRateHz = 8000;
@@ -65,18 +64,14 @@
                 continue;
             }
             sp<IStreamIn> stream;
+            StreamHelper<IStreamIn> helper(stream);
             AudioConfig suggestedConfig{};
-            ASSERT_OK(getDevice()->openInputStream(ioHandle, microphone.deviceAddress, config,
-                                                   flags, initMetadata,
-                                                   returnIn(res, stream, suggestedConfig)));
-            if (res != Result::OK) {
-                ASSERT_TRUE(stream == nullptr);
-                AudioConfig suggestedConfigRetry{};
-                ASSERT_OK(getDevice()->openInputStream(
-                        ioHandle, microphone.deviceAddress, suggestedConfig, flags, initMetadata,
-                        returnIn(res, stream, suggestedConfigRetry)));
-            }
-            ASSERT_OK(res);
+            ASSERT_NO_FATAL_FAILURE(helper.open(
+                    [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                        return getDevice()->openInputStream(handle, microphone.deviceAddress,
+                                                            config, flags, initMetadata, cb);
+                    },
+                    config, &res, &suggestedConfig));
             hidl_vec<MicrophoneInfo> activeMicrophones;
             Result readRes;
             typedef MessageQueue<IStreamIn::ReadParameters, kSynchronizedReadWrite> CommandMQ;
@@ -110,13 +105,8 @@
                 ASSERT_OK(res);
                 ASSERT_NE(0U, activeMicrophones.size());
             }
-            stream->close();
-#if MAJOR_VERSION <= 5
-            // Workaround for b/139329877. Ensures the stream gets closed on the audio hal side.
-            stream.clear();
-            IPCThreadState::self()->flushCommands();
-            usleep(1000);
-#endif
+            helper.close(true /*clear*/, &res);
+            ASSERT_OK(res);
             if (efGroup) {
                 EventFlag::deleteEventFlag(&efGroup);
             }
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 7e931ff..22e60be 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -145,3 +145,49 @@
     }();
     return parameters;
 }
+
+TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
+    doc::test("Verify that a device can't be closed if there are streams opened");
+    DeviceAddress address{.device = AudioDevice::OUT_DEFAULT};
+    AudioConfig config{};
+    auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
+    SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
+    sp<IStreamOut> stream;
+    StreamHelper<IStreamOut> helper(stream);
+    AudioConfig suggestedConfig{};
+    ASSERT_NO_FATAL_FAILURE(helper.open(
+            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                return getDevice()->openOutputStream(handle, address, config, flags, initMetadata,
+                                                     cb);
+            },
+            config, &res, &suggestedConfig));
+    ASSERT_RESULT(Result::INVALID_STATE, getDevice()->close());
+    ASSERT_NO_FATAL_FAILURE(helper.close(true /*clear*/, &res));
+    ASSERT_OK(getDevice()->close());
+    ASSERT_TRUE(resetDevice());
+}
+
+TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
+    doc::test("Verify that a device can't be closed if there are streams opened");
+    auto module = getCachedPolicyConfig().getModuleFromName(getDeviceName());
+    if (module->getInputProfiles().empty()) {
+        GTEST_SKIP() << "Device doesn't have input profiles";
+    }
+    DeviceAddress address{.device = AudioDevice::IN_DEFAULT};
+    AudioConfig config{};
+    auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
+    SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
+    sp<IStreamIn> stream;
+    StreamHelper<IStreamIn> helper(stream);
+    AudioConfig suggestedConfig{};
+    ASSERT_NO_FATAL_FAILURE(helper.open(
+            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                return getDevice()->openInputStream(handle, address, config, flags, initMetadata,
+                                                    cb);
+            },
+            config, &res, &suggestedConfig));
+    ASSERT_RESULT(Result::INVALID_STATE, getDevice()->close());
+    ASSERT_NO_FATAL_FAILURE(helper.close(true /*clear*/, &res));
+    ASSERT_OK(getDevice()->close());
+    ASSERT_TRUE(resetDevice());
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 6fc9339..d0d39e8 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -718,12 +718,6 @@
                 ::testing::Values(AudioInputFlag::NONE)),
         &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-        SupportedInputBufferSize, RequiredInputBufferSizeTest,
-        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
-                           ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig()),
-                           ::testing::Values(AudioInputFlag::NONE)),
-        &DeviceConfigParameterToString);
-INSTANTIATE_TEST_CASE_P(
         RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
         ::testing::Combine(
                 ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
@@ -815,62 +809,84 @@
 ////////////////////////// open{Output,Input}Stream //////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
+// This class is also used by some device tests.
 template <class Stream>
-class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
-  protected:
+class StreamHelper {
+  public:
+    // StreamHelper doesn't own the stream, this is for simpler stream lifetime management.
+    explicit StreamHelper(sp<Stream>& stream) : mStream(stream) {}
     template <class Open>
-    void testOpen(Open openStream, const AudioConfig& config) {
+    void open(Open openStream, const AudioConfig& config, Result* res,
+              AudioConfig* suggestedConfigPtr) {
         // 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) {
+        bool retryWithSuggestedConfig = true;
+        if (suggestedConfigPtr == nullptr) {
+            suggestedConfigPtr = &suggestedConfig;
+            retryWithSuggestedConfig = false;
+        }
+        ASSERT_OK(openStream(ioHandle, config, returnIn(*res, mStream, *suggestedConfigPtr)));
+        switch (*res) {
             case Result::OK:
-                ASSERT_TRUE(stream != nullptr);
-                audioConfig = config;
+                ASSERT_TRUE(mStream != nullptr);
+                *suggestedConfigPtr = 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;
+                ASSERT_TRUE(mStream == nullptr);
+                if (retryWithSuggestedConfig) {
+                    AudioConfig suggestedConfigRetry;
+                    ASSERT_OK(openStream(ioHandle, *suggestedConfigPtr,
+                                         returnIn(*res, mStream, suggestedConfigRetry)));
+                    ASSERT_OK(*res);
+                    ASSERT_TRUE(mStream != nullptr);
+                }
                 break;
             default:
-                FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+                FAIL() << "Invalid return status: " << ::testing::PrintToString(*res);
         }
+    }
+    void close(bool clear, Result* res) {
+        auto ret = mStream->close();
+        EXPECT_TRUE(ret.isOk());
+        *res = ret;
+        if (clear) {
+            mStream.clear();
+#if MAJOR_VERSION <= 5
+            // FIXME: there is no way to know when the remote IStream is being destroyed
+            //        Binder does not support testing if an object is alive, thus
+            //        wait for 100ms to let the binder destruction propagates and
+            //        the remote device has the time to be destroyed.
+            //        flushCommand makes sure all local command are sent, thus should reduce
+            //        the latency between local and remote destruction.
+            IPCThreadState::self()->flushCommands();
+            usleep(100 * 1000);
+#endif
+        }
+    }
+
+  private:
+    sp<Stream>& mStream;
+};
+
+template <class Stream>
+class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+  protected:
+    OpenStreamTest() : AudioHidlTestWithDeviceConfigParameter(), helper(stream) {}
+    template <class Open>
+    void testOpen(Open openStream, const AudioConfig& config) {
+        // TODO: only allow failure for RecommendedPlaybackAudioConfig
+        ASSERT_NO_FATAL_FAILURE(helper.open(openStream, config, &res, &audioConfig));
         open = true;
     }
 
-    Return<Result> closeStream() {
+    Result closeStream(bool clear = true) {
         open = false;
-        auto res = stream->close();
-        stream.clear();
-        waitForStreamDestruction();
+        helper.close(clear, &res);
         return res;
     }
 
-    static void waitForStreamDestruction() {
-#if MAJOR_VERSION <= 5
-        // FIXME: there is no way to know when the remote IStream is being destroyed
-        //        Binder does not support testing if an object is alive, thus
-        //        wait for 100ms to let the binder destruction propagates and
-        //        the remote device has the time to be destroyed.
-        //        flushCommand makes sure all local command are sent, thus should reduce
-        //        the latency between local and remote destruction.
-        IPCThreadState::self()->flushCommands();
-        usleep(100 * 1000);
-#endif
-    }
-
   private:
     void TearDown() override {
         if (open) {
@@ -883,6 +899,7 @@
     AudioConfig audioConfig;
     DeviceAddress address = {};
     sp<Stream> stream;
+    StreamHelper<Stream> helper;
     bool open = false;
 };
 
@@ -931,12 +948,6 @@
                 ::testing::Values(AudioOutputFlag::NONE)),
         &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-        SupportedOutputStreamConfig, OutputStreamTest,
-        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
-                           ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig()),
-                           ::testing::Values(AudioOutputFlag::NONE)),
-        &DeviceConfigParameterToString);
-INSTANTIATE_TEST_CASE_P(
         RecommendedOutputStreamConfigSupport, OutputStreamTest,
         ::testing::Combine(
                 ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
@@ -946,7 +957,7 @@
 #elif MAJOR_VERSION >= 6
 // For V6 and above test according to the audio policy manager configuration.
 // This is more correct as CDD is written from the apps perspective.
-// Audio system provides necessary format conversions for the missing configurations.
+// Audio system provides necessary format conversions for missing configurations.
 INSTANTIATE_TEST_CASE_P(DeclaredOutputStreamConfigSupport, OutputStreamTest,
                         ::testing::ValuesIn(getOutputDeviceConfigParameters()),
                         &DeviceConfigParameterToString);
@@ -992,12 +1003,6 @@
                 ::testing::Values(AudioInputFlag::NONE)),
         &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-        SupportedInputStreamConfig, InputStreamTest,
-        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
-                           ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig()),
-                           ::testing::Values(AudioInputFlag::NONE)),
-        &DeviceConfigParameterToString);
-INSTANTIATE_TEST_CASE_P(
         RecommendedInputStreamConfigSupport, InputStreamTest,
         ::testing::Combine(
                 ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
@@ -1007,7 +1012,7 @@
 #elif MAJOR_VERSION >= 6
 // For V6 and above test according to the audio policy manager configuration.
 // This is more correct as CDD is written from the apps perspective.
-// Audio system provides necessary format conversions for the missing configurations.
+// Audio system provides necessary format conversions for missing configurations.
 INSTANTIATE_TEST_CASE_P(DeclaredInputStreamConfigSupport, InputStreamTest,
                         ::testing::ValuesIn(getInputDeviceConfigParameters()),
                         &DeviceConfigParameterToString);
@@ -1196,11 +1201,8 @@
 TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
 // clang-format off
 TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice",
-        auto streamCopy = stream;
-        ASSERT_OK(closeStream());
-        ASSERT_RESULT(Result::INVALID_STATE, streamCopy->close());
-        streamCopy.clear();
-        waitForStreamDestruction())
+        ASSERT_OK(closeStream(false /*clear*/));
+        ASSERT_EQ(Result::INVALID_STATE, closeStream()))
 // clang-format on
 
 static void testMmapBufferOfInvalidSize(IStream* stream) {
diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h
index 48aae8c..a2f4116 100644
--- a/audio/core/all-versions/vts/functional/ConfigHelper.h
+++ b/audio/core/all-versions/vts/functional/ConfigHelper.h
@@ -57,12 +57,6 @@
                                   {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() {
         if (!primaryHasMic()) return {};
         return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
@@ -73,11 +67,6 @@
         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 {};
-    }
 
     static vector<AudioConfig> combineAudioConfig(vector<audio_channel_mask_t> channelMasks,
                                                   vector<uint32_t> sampleRates,
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 0afa779..e11e123 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -307,12 +307,11 @@
 Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
                                     GetCurrentConfigSuccessCallback onSuccess) {
     uint32_t halCmd = featureId;
-    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)];
-    memset(halResult, 0, sizeof(halResult));
+    std::vector<uint32_t> halResult(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize), 0);
     uint32_t halResultSize = 0;
-    return sendCommandReturningStatusAndData(EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG",
-                                             sizeof(uint32_t), &halCmd, &halResultSize, halResult,
-                                             sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
+    return sendCommandReturningStatusAndData(
+            EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", sizeof(uint32_t), &halCmd,
+            &halResultSize, &halResult[0], sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
 }
 
 Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData,
@@ -339,8 +338,7 @@
                                        GetSupportedConfigsSuccessCallback onSuccess) {
     uint32_t halCmd[2] = {featureId, maxConfigs};
     uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
-    uint8_t halResult[halResultSize];
-    memset(&halResult[0], 0, halResultSize);
+    std::vector<uint8_t> halResult(static_cast<size_t>(halResultSize), 0);
     return sendCommandReturningStatusAndData(
         EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
         halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] {
@@ -519,9 +517,9 @@
     uint32_t halDataSize;
     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
     uint32_t halResultSize = halDataSize;
-    uint32_t halResult[volumes.size()];
+    std::vector<uint32_t> halResult(volumes.size(), 0);
     Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize,
-                                             &halData[0], &halResultSize, halResult);
+                                             &halData[0], &halResultSize, &halResult[0]);
     hidl_vec<uint32_t> result;
     if (retval == Result::OK) {
         result.setToExternal(&halResult[0], halResultSize);
@@ -581,8 +579,6 @@
 }
 
 Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
-    memset(halResult, 0, sizeof(halResult));
     EffectAuxChannelsConfig result;
     Result retval = getCurrentConfigImpl(
         EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) {
@@ -594,11 +590,12 @@
 }
 
 Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
-    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
+    std::vector<uint32_t> halCmd(
+            alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t)), 0);
     halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
     effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
-                                      "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd);
+                                      "SET_FEATURE_CONFIG AUX_CHANNELS", halCmd.size(), &halCmd[0]);
 }
 
 Return<Result> Effect::setAudioSource(AudioSource source) {
@@ -692,12 +689,11 @@
 
 Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
                                                   const hidl_vec<uint8_t>& configData) {
-    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())];
-    memset(halCmd, 0, sizeof(halCmd));
+    std::vector<uint32_t> halCmd(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size()), 0);
     halCmd[0] = featureId;
     memcpy(&halCmd[1], &configData[0], configData.size());
     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG",
-                                      sizeof(halCmd), halCmd);
+                                      halCmd.size(), &halCmd[0]);
 }
 
 Return<Result> Effect::close() {
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index ed09859..f9c25d1 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -58,6 +58,7 @@
     defaults: ["vhal_v2_0_defaults"],
     srcs: [
         "impl/vhal_v2_0/CommConn.cpp",
+        "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
         "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
         "impl/vhal_v2_0/VehicleEmulator.cpp",
         "impl/vhal_v2_0/PipeComm.cpp",
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index d1fd555..127eb98 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -20,8 +20,9 @@
 
 #include <iostream>
 
-#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/EmulatedVehicleConnector.h>
 #include <vhal_v2_0/EmulatedVehicleHal.h>
+#include <vhal_v2_0/VehicleHalManager.h>
 
 using namespace android;
 using namespace android::hardware;
@@ -29,9 +30,11 @@
 
 int main(int /* argc */, char* /* argv */ []) {
     auto store = std::make_unique<VehiclePropertyStore>();
-    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());
+    auto connector = impl::makeEmulatedPassthroughConnector();
+    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
     auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
     auto service = std::make_unique<VehicleHalManager>(hal.get());
+    connector->setValuePool(hal->getValuePool());
 
     configureRpcThreadpool(4, true /* callerWillJoin */);
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
new file mode 100644
index 0000000..168999d
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "DefaultConfig.h"
+#include "EmulatedVehicleConnector.h"
+#include "JsonFakeValueGenerator.h"
+#include "LinearFakeValueGenerator.h"
+#include "Obd2SensorStore.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value) {
+    if (!mPropCallback) {
+        LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
+        return;
+    }
+    return mPropCallback(value);
+}
+
+void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
+    if (mPropCallback) {
+        LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
+        return;
+    }
+    mPropCallback = std::move(callback);
+}
+
+GeneratorHub* EmulatedVehicleServer::getGenerator() {
+    return &mGeneratorHub;
+}
+
+VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const {
+    if (!mValuePool) {
+        LOG(WARNING) << __func__ << ": Value pool not set!";
+    }
+    return mValuePool;
+}
+
+void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) {
+    if (!valuePool) {
+        LOG(WARNING) <<  __func__ << ": Setting value pool to nullptr!";
+    }
+    mValuePool = valuePool;
+}
+
+void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) {
+    LOG(DEBUG) << __func__ << ": " << toString(value);
+    auto updatedPropValue = getValuePool()->obtain(value);
+    if (updatedPropValue) {
+        updatedPropValue->timestamp = value.timestamp;
+        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
+        onPropertyValueFromCar(*updatedPropValue);
+    }
+}
+
+std::vector<VehiclePropConfig> EmulatedVehicleServer::onGetAllPropertyConfig() const {
+    std::vector<VehiclePropConfig> vehiclePropConfigs;
+    constexpr size_t numOfVehiclePropConfigs =
+            sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
+    vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
+    for (auto& it : kVehicleProperties) {
+        vehiclePropConfigs.emplace_back(it.config);
+    }
+    return vehiclePropConfigs;
+}
+
+StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+    LOG(INFO) << __func__;
+    const auto& v = request.value;
+    if (!v.int32Values.size()) {
+        LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
+        return StatusCode::INVALID_ARG;
+    }
+
+    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
+
+    switch (command) {
+        case FakeDataCommand::StartLinear: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
+            if (v.int32Values.size() < 2) {
+                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+                return StatusCode::INVALID_ARG;
+            }
+            if (!v.int64Values.size()) {
+                LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
+                return StatusCode::INVALID_ARG;
+            }
+            if (v.floatValues.size() < 3) {
+                LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
+                      << v.floatValues.size();
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            getGenerator()->registerGenerator(cookie,
+                                              std::make_unique<LinearFakeValueGenerator>(request));
+            break;
+        }
+        case FakeDataCommand::StartJson: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
+            if (v.stringValue.empty()) {
+                LOG(ERROR) << __func__ << ": path to JSON file is missing";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            getGenerator()->registerGenerator(cookie,
+                                              std::make_unique<JsonFakeValueGenerator>(request));
+            break;
+        }
+        case FakeDataCommand::StopLinear: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
+            if (v.int32Values.size() < 2) {
+                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            getGenerator()->unregisterGenerator(cookie);
+            break;
+        }
+        case FakeDataCommand::StopJson: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
+            if (v.stringValue.empty()) {
+                LOG(ERROR) << __func__ << ": path to JSON file is missing";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            getGenerator()->unregisterGenerator(cookie);
+            break;
+        }
+        case FakeDataCommand::KeyPress: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
+            int32_t keyCode = request.value.int32Values[2];
+            int32_t display = request.value.int32Values[3];
+            // Send back to HAL
+            onPropertyValueFromCar(
+                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
+            onPropertyValueFromCar(
+                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
+            return StatusCode::INVALID_ARG;
+        }
+    }
+    return StatusCode::OK;
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq(
+    VehicleApPowerStateReq state, int32_t param) {
+    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
+    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+    req->areaId = 0;
+    req->timestamp = elapsedRealtimeNano();
+    req->status = VehiclePropertyStatus::AVAILABLE;
+    req->value.int32Values[0] = toInt(state);
+    req->value.int32Values[1] = param;
+    return req;
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp(
+        VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
+    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
+    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
+    keyEvent->areaId = 0;
+    keyEvent->timestamp = elapsedRealtimeNano();
+    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
+    keyEvent->value.int32Values[0] = toInt(action);
+    keyEvent->value.int32Values[1] = keyCode;
+    keyEvent->value.int32Values[2] = targetDisplay;
+    return keyEvent;
+}
+
+StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) {
+    // Some properties need to be treated non-trivially
+    switch (value.prop) {
+        case AP_POWER_STATE_REPORT:
+            switch (value.value.int32Values[0]) {
+                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
+                case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
+                    // CPMS is in WAIT_FOR_VHAL state, simply move to ON
+                    // Send back to HAL
+                    onPropertyValueFromCar(
+                            *createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
+                    break;
+                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
+                    // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
+                    // Send back to HAL
+                    onPropertyValueFromCar(
+                            *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
+                    break;
+                case toInt(VehicleApPowerStateReport::ON):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
+                    // Do nothing
+                    break;
+                default:
+                    // Unknown state
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+
+    // In the real vhal, the value will be sent to Car ECU.
+    // We just pretend it is done here.
+    return StatusCode::OK;
+}
+
+StatusCode EmulatedVehicleServer::onSetPropertyFromVehicle(const VehiclePropValue& value) {
+    if (value.prop == kGenerateFakeDataControllingProperty) {
+        auto status = handleGenerateFakeDataRequest(value);
+        return status;
+    } else {
+        // Send back to HAL
+        onPropertyValueFromCar(value);
+        return StatusCode::OK;
+    }
+}
+
+EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
+    return std::make_unique<EmulatedPassthroughConnector>();
+}
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
new file mode 100644
index 0000000..d424cd8
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
+
+#include <vhal_v2_0/VehicleConnector.h>
+#include <vhal_v2_0/VehicleHal.h>
+
+#include "GeneratorHub.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+// Extension of the client/server interfaces for emulated vehicle
+
+class EmulatedVehicleClient : public IVehicleClient {
+  public:
+    // Type of callback function for handling the new property values
+    using PropertyCallBackType = std::function<void(const VehiclePropValue&)>;
+
+    // Method from IVehicleClient
+    void onPropertyValue(const VehiclePropValue& value) override;
+
+    // Request to change the value on the VEHICLE side (for testing)
+    virtual StatusCode setPropertyFromVehicle(const VehiclePropValue& value) = 0;
+
+    void registerPropertyValueCallback(PropertyCallBackType&& callback);
+
+  private:
+    PropertyCallBackType mPropCallback;
+};
+
+class EmulatedVehicleServer : public IVehicleServer {
+  public:
+    // Methods from IVehicleServer
+
+    std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
+
+    StatusCode onSetProperty(const VehiclePropValue& value) override;
+
+    // Process the request to change the value on the VEHICLE side (for testing)
+    StatusCode onSetPropertyFromVehicle(const VehiclePropValue& value);
+
+    // Set the Property Value Pool used in this server
+    void setValuePool(VehiclePropValuePool* valuePool);
+
+  private:
+    GeneratorHub* getGenerator();
+
+    VehiclePropValuePool* getValuePool() const;
+
+    void onFakeValueGenerated(const VehiclePropValue& value);
+
+    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
+
+    VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
+
+    VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action,
+                                                         int32_t keyCode, int32_t targetDisplay);
+
+    // private data members
+
+    GeneratorHub mGeneratorHub{
+            std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};
+
+    VehiclePropValuePool* mValuePool{nullptr};
+};
+
+class EmulatedPassthroughConnector
+    : public IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer> {
+  public:
+    StatusCode setPropertyFromVehicle(const VehiclePropValue& value) override {
+        return this->onSetPropertyFromVehicle(value);
+    }
+};
+
+// Helper functions
+
+using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
+
+EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index dc051d8..6508efe 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -87,17 +87,19 @@
     return sensorStore;
 }
 
-EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore,
+                                       EmulatedVehicleClient* client)
     : mPropStore(propStore),
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
       mRecurrentTimer(
           std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
-      mGeneratorHub(
-          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
+      mVehicleClient(client) {
     initStaticConfig();
     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
         mPropStore->registerProperty(kVehicleProperties[i].config);
     }
+    mVehicleClient->registerPropertyValueCallback(
+        std::bind(&EmulatedVehicleHal::onPropertyValue, this, std::placeholders::_1));
 }
 
 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
@@ -162,7 +164,8 @@
     }
 
     if (propValue.prop == kGenerateFakeDataControllingProperty) {
-        StatusCode status = handleGenerateFakeDataRequest(propValue);
+        // send the generator controlling request to the server
+        auto status = mVehicleClient->setPropertyFromVehicle(propValue);
         if (status != StatusCode::OK) {
             return status;
         }
@@ -186,29 +189,6 @@
                 // Placeholder for future implementation of VMS property in the default hal. For
                 // now, just returns OK; otherwise, hal clients crash with property not supported.
                 return StatusCode::OK;
-            case AP_POWER_STATE_REPORT:
-                switch (propValue.value.int32Values[0]) {
-                    case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
-                    case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
-                        // CPMS is in WAIT_FOR_VHAL state, simply move to ON
-                        doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
-                        break;
-                    case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
-                        // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
-                        doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
-                        break;
-                    case toInt(VehicleApPowerStateReport::ON):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
-                        // Do nothing
-                        break;
-                    default:
-                        // Unknown state
-                        break;
-                }
-                break;
         }
     }
 
@@ -231,10 +211,16 @@
     /**
      * After checking all conditions, such as the property is available, a real vhal will
      * sent the events to Car ECU to take actions.
-     * Google HAL will just add a timestamp for the value and triggle the callback to android.
      */
     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue);
     updatedPropValue->timestamp = elapsedRealtimeNano();
+
+    // Send the value to the vehicle server, the server will talk to the (real or emulated) car
+    auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue);
+    if (setValueStatus != StatusCode::OK) {
+        return setValueStatus;
+    }
+
     if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
         return StatusCode::INTERNAL_ERROR;
     }
@@ -361,144 +347,19 @@
 }
 
 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
-    static constexpr bool shouldUpdateStatus = true;
-
-    if (propValue.prop == kGenerateFakeDataControllingProperty) {
-        StatusCode status = handleGenerateFakeDataRequest(propValue);
-        if (status != StatusCode::OK) {
-            return false;
-        }
-    }
-
-    if (mPropStore->writeValue(propValue, shouldUpdateStatus)) {
-        doHalEvent(getValuePool()->obtain(propValue));
-        return true;
-    } else {
-        return false;
-    }
+    return mVehicleClient->setPropertyFromVehicle(propValue) == StatusCode::OK;
 }
 
 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const  {
     return mPropStore->readAllValues();
 }
 
-StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
-    ALOGI("%s", __func__);
-    const auto& v = request.value;
-    if (!v.int32Values.size()) {
-        ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
-        return StatusCode::INVALID_ARG;
-    }
-
-    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
-
-    switch (command) {
-        case FakeDataCommand::StartLinear: {
-            ALOGI("%s, FakeDataCommand::StartLinear", __func__);
-            if (v.int32Values.size() < 2) {
-                ALOGE("%s: expected property ID in int32Values", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            if (!v.int64Values.size()) {
-                ALOGE("%s: interval is not provided in int64Values", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            if (v.floatValues.size() < 3) {
-                ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
-                      v.floatValues.size());
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = v.int32Values[1];
-            mGeneratorHub.registerGenerator(cookie,
-                                            std::make_unique<LinearFakeValueGenerator>(request));
-            break;
-        }
-        case FakeDataCommand::StartJson: {
-            ALOGI("%s, FakeDataCommand::StartJson", __func__);
-            if (v.stringValue.empty()) {
-                ALOGE("%s: path to JSON file is missing", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = std::hash<std::string>()(v.stringValue);
-            mGeneratorHub.registerGenerator(cookie,
-                                            std::make_unique<JsonFakeValueGenerator>(request));
-            break;
-        }
-        case FakeDataCommand::StopLinear: {
-            ALOGI("%s, FakeDataCommand::StopLinear", __func__);
-            if (v.int32Values.size() < 2) {
-                ALOGE("%s: expected property ID in int32Values", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = v.int32Values[1];
-            mGeneratorHub.unregisterGenerator(cookie);
-            break;
-        }
-        case FakeDataCommand::StopJson: {
-            ALOGI("%s, FakeDataCommand::StopJson", __func__);
-            if (v.stringValue.empty()) {
-                ALOGE("%s: path to JSON file is missing", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = std::hash<std::string>()(v.stringValue);
-            mGeneratorHub.unregisterGenerator(cookie);
-            break;
-        }
-        case FakeDataCommand::KeyPress: {
-            ALOGI("%s, FakeDataCommand::KeyPress", __func__);
-            int32_t keyCode = request.value.int32Values[2];
-            int32_t display = request.value.int32Values[3];
-            doHalEvent(
-                createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
-            doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
-            break;
-        }
-        default: {
-            ALOGE("%s: unexpected command: %d", __func__, command);
-            return StatusCode::INVALID_ARG;
-        }
-    }
-    return StatusCode::OK;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq(
-    VehicleApPowerStateReq state, int32_t param) {
-    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
-    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
-    req->areaId = 0;
-    req->timestamp = elapsedRealtimeNano();
-    req->status = VehiclePropertyStatus::AVAILABLE;
-    req->value.int32Values[0] = toInt(state);
-    req->value.int32Values[1] = param;
-    return req;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
-    VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
-    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
-    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
-    keyEvent->areaId = 0;
-    keyEvent->timestamp = elapsedRealtimeNano();
-    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
-    keyEvent->value.int32Values[0] = toInt(action);
-    keyEvent->value.int32Values[1] = keyCode;
-    keyEvent->value.int32Values[2] = targetDisplay;
-    return keyEvent;
-}
-
-void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
-    ALOGD("%s: %s", __func__, toString(value).c_str());
-    static constexpr bool shouldUpdateStatus = false;
-
+void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value) {
+    static constexpr bool shouldUpdateStatus = true;
     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
-    if (updatedPropValue) {
-        updatedPropValue->timestamp = value.timestamp;
-        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
-        mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
-        auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
-        if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
-            doHalEvent(std::move(updatedPropValue));
-        }
+
+    if (mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
+        doHalEvent(std::move(updatedPropValue));
     }
 }
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index 78895e3..98315ec 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -30,6 +30,7 @@
 #include "vhal_v2_0/VehiclePropertyStore.h"
 
 #include "DefaultConfig.h"
+#include "EmulatedVehicleConnector.h"
 #include "GeneratorHub.h"
 #include "VehicleEmulator.h"
 
@@ -44,7 +45,8 @@
 /** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
 class EmulatedVehicleHal : public EmulatedVehicleHalIface {
 public:
-    EmulatedVehicleHal(VehiclePropertyStore* propStore);
+    EmulatedVehicleHal(VehiclePropertyStore* propStore,
+                       EmulatedVehicleClient* client);
     ~EmulatedVehicleHal() = default;
 
     //  Methods from VehicleHal
@@ -66,10 +68,7 @@
     }
 
     StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
-    void onFakeValueGenerated(const VehiclePropValue& value);
-    VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
-    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
-                                             int32_t targetDisplay);
+    void onPropertyValue(const VehiclePropValue& value);
 
     void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
     bool isContinuousProperty(int32_t propId) const;
@@ -85,7 +84,7 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
-    GeneratorHub mGeneratorHub;
+    EmulatedVehicleClient* mVehicleClient;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
index 6754843..2eedecd 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
@@ -29,3 +29,64 @@
     ],
     srcs: ["VehicleHalProto.proto"]
 }
+
+cc_library_static {
+    name: "android.hardware.automotive.vehicle@2.0-grpc",
+    vendor: true,
+    include_dirs: [
+        "external/protobuf/src",
+    ],
+    generated_headers: [
+        "DefaultVehicleHalProtoStub_h",
+    ],
+    export_generated_headers: [
+        "DefaultVehicleHalProtoStub_h",
+    ],
+    generated_sources: [
+        "DefaultVehicleHalProtoStub_cc",
+    ],
+    shared_libs: [
+        "libgrpc++_unsecure",
+    ],
+    cflags: [
+        "-Wno-unused-parameter"
+    ],
+}
+
+genrule {
+    name: "DefaultVehicleHalProtoStub_h",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "VehicleHalProto.proto",
+        "VehicleServer.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.h",
+        "VehicleHalProto.grpc.pb.h",
+        "VehicleServer.pb.h",
+        "VehicleServer.grpc.pb.h",
+    ],
+}
+
+genrule {
+    name: "DefaultVehicleHalProtoStub_cc",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "VehicleHalProto.proto",
+        "VehicleServer.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.cc",
+        "VehicleHalProto.grpc.pb.cc",
+        "VehicleServer.pb.cc",
+        "VehicleServer.grpc.pb.cc",
+    ],
+}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 2ef64fb..04df5a8 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -15,7 +15,6 @@
  */
 
 syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
 
 package emulator;
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
new file mode 100644
index 0000000..7ce3c32
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package emulator;
+
+import "google/protobuf/empty.proto";
+import "VehicleHalProto.proto";
+
+// correspond to StatusCode defined in types.hal
+enum VehicleHalStatusCode {
+    OK                                  = 0;
+    TRY_AGAIN                           = 1;
+    INVALID_ARG                         = 2;
+    NOT_AVAILABLE                       = 3;
+    ACCESS_DENIED                       = 4;
+    INTERNAL_ERROR                      = 5;
+}
+
+message VehicleHalCallStatus {
+    required VehicleHalStatusCode status_code      = 1;
+}
+
+service VehicleServer {
+    rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {}
+
+    // Change the property value of the vehicle
+    rpc SetProperty(VehiclePropValue) returns (VehicleHalCallStatus) {}
+
+    // Start a vehicle property value stream
+    rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValue) {}
+}
+
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 279d5cd..24fcf76 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2381,6 +2381,26 @@
         | VehiclePropertyType:BOOLEAN
         | VehicleArea:GLOBAL),
 
+    /**
+     * Allow disabling optional featurs from vhal.
+     *
+     * This property reports optional features that should be disabled.
+     * All allowed optional features for the system is declared in Car service overlay,
+     * config_allowed_optional_car_features.
+     * This property allows disabling features defined in the overlay. Without this property,
+     * all the features declared in the overlay will be enabled.
+     *
+     * Value read should include all features disabled with ',' separation.
+     * ex) "com.android.car.user.CarUserNoticeService,storage_monitoring"
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    DISABLED_OPTIONAL_FEATURES = (
+        0x0F06
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:STRING
+        | VehicleArea:GLOBAL),
+
 };
 
 /**
diff --git a/biometrics/face/1.0/vts/functional/Android.bp b/biometrics/face/1.0/vts/functional/Android.bp
index fa68c4e..f2598a7 100644
--- a/biometrics/face/1.0/vts/functional/Android.bp
+++ b/biometrics/face/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalBiometricsFaceV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.biometrics.face@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
index a4e95ed..7ac44a4 100644
--- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -20,9 +20,10 @@
 #include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <chrono>
 #include <cstdint>
@@ -124,27 +125,11 @@
     }
 };
 
-// Test environment for the BiometricsFace HAL.
-class FaceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // Get the test environment singleton.
-    static FaceHidlEnvironment* Instance() {
-        static FaceHidlEnvironment* instance = new FaceHidlEnvironment;
-        return instance;
-    }
-
-    void registerTestServices() override { registerTestService<IBiometricsFace>(); }
-
-  private:
-    FaceHidlEnvironment() = default;
-};
-
 // Test class for the BiometricsFace HAL.
-class FaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
-        mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFace>(
-                FaceHidlEnvironment::Instance()->getServiceName<IBiometricsFace>());
+        mService = IBiometricsFace::getService(GetParam());
         ASSERT_NE(mService, nullptr);
         mCallback = new FaceCallback();
         mCallback->SetWaitTimeoutDefault(kTimeout);
@@ -167,7 +152,7 @@
 
 // generateChallenge should always return a unique, cryptographically secure,
 // non-zero number.
-TEST_F(FaceHidlTest, GenerateChallengeTest) {
+TEST_P(FaceHidlTest, GenerateChallengeTest) {
     std::map<uint64_t, int> m;
     for (int i = 0; i < kGenerateChallengeIterations; ++i) {
         Return<void> ret =
@@ -182,7 +167,7 @@
 }
 
 // enroll with an invalid (all zeroes) HAT should fail.
-TEST_F(FaceHidlTest, EnrollZeroHatTest) {
+TEST_P(FaceHidlTest, EnrollZeroHatTest) {
     // Filling HAT with zeros
     hidl_vec<uint8_t> token(69);
     for (size_t i = 0; i < 69; i++) {
@@ -200,7 +185,7 @@
 }
 
 // enroll with an invalid HAT should fail.
-TEST_F(FaceHidlTest, EnrollGarbageHatTest) {
+TEST_P(FaceHidlTest, EnrollGarbageHatTest) {
     // Filling HAT with pseudorandom invalid data.
     // Using default seed to make the test reproducible.
     std::mt19937 gen(std::mt19937::default_seed);
@@ -221,7 +206,7 @@
 }
 
 // setFeature with an invalid (all zeros) HAT should fail.
-TEST_F(FaceHidlTest, SetFeatureZeroHatTest) {
+TEST_P(FaceHidlTest, SetFeatureZeroHatTest) {
     hidl_vec<uint8_t> token(69);
     for (size_t i = 0; i < 69; i++) {
         token[i] = 0;
@@ -232,7 +217,7 @@
 }
 
 // setFeature with an invalid HAT should fail.
-TEST_F(FaceHidlTest, SetFeatureGarbageHatTest) {
+TEST_P(FaceHidlTest, SetFeatureGarbageHatTest) {
     // Filling HAT with pseudorandom invalid data.
     // Using default seed to make the test reproducible.
     std::mt19937 gen(std::mt19937::default_seed);
@@ -254,16 +239,16 @@
     ASSERT_TRUE(res.isOk());
 }
 
-TEST_F(FaceHidlTest, GetFeatureRequireAttentionTest) {
+TEST_P(FaceHidlTest, GetFeatureRequireAttentionTest) {
     assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_ATTENTION);
 }
 
-TEST_F(FaceHidlTest, GetFeatureRequireDiversityTest) {
+TEST_P(FaceHidlTest, GetFeatureRequireDiversityTest) {
     assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_DIVERSITY);
 }
 
 // revokeChallenge should always return within the timeout
-TEST_F(FaceHidlTest, RevokeChallengeTest) {
+TEST_P(FaceHidlTest, RevokeChallengeTest) {
     auto start = std::chrono::system_clock::now();
     Return<Status> ret = mService->revokeChallenge();
     auto elapsed = std::chrono::system_clock::now() - start;
@@ -272,14 +257,14 @@
 }
 
 // The call to getAuthenticatorId should succeed.
-TEST_F(FaceHidlTest, GetAuthenticatorIdTest) {
+TEST_P(FaceHidlTest, GetAuthenticatorIdTest) {
     Return<void> ret = mService->getAuthenticatorId(
             [](const OptionalUint64& res) { ASSERT_EQ(Status::OK, res.status); });
     ASSERT_TRUE(ret.isOk());
 }
 
 // The call to enumerate should succeed.
-TEST_F(FaceHidlTest, EnumerateTest) {
+TEST_P(FaceHidlTest, EnumerateTest) {
     Return<Status> ret = mService->enumerate();
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
     auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate);
@@ -288,21 +273,21 @@
 }
 
 // The call to remove should succeed for any faceId
-TEST_F(FaceHidlTest, RemoveFaceTest) {
+TEST_P(FaceHidlTest, RemoveFaceTest) {
     // Remove a face
     Return<Status> ret = mService->remove(kFaceId);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
 }
 
 // Remove should accept 0 to delete all faces
-TEST_F(FaceHidlTest, RemoveAllFacesTest) {
+TEST_P(FaceHidlTest, RemoveAllFacesTest) {
     // Remove all faces
     Return<Status> ret = mService->remove(0);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
 }
 
 // Active user should successfully set to a writable location.
-TEST_F(FaceHidlTest, SetActiveUserTest) {
+TEST_P(FaceHidlTest, SetActiveUserTest) {
     // Create an active user
     Return<Status> ret = mService->setActiveUser(2, kFacedataDir);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
@@ -313,7 +298,7 @@
 }
 
 // Active user should fail to set to an unwritable location.
-TEST_F(FaceHidlTest, SetActiveUserUnwritableTest) {
+TEST_P(FaceHidlTest, SetActiveUserUnwritableTest) {
     // Create an active user to an unwritable location (device root dir)
     Return<Status> ret = mService->setActiveUser(3, "/");
     ASSERT_NE(Status::OK, static_cast<Status>(ret));
@@ -324,7 +309,7 @@
 }
 
 // Active user should fail to set to a null location.
-TEST_F(FaceHidlTest, SetActiveUserNullTest) {
+TEST_P(FaceHidlTest, SetActiveUserNullTest) {
     // Create an active user to a null location.
     Return<Status> ret = mService->setActiveUser(4, nullptr);
     ASSERT_NE(Status::OK, static_cast<Status>(ret));
@@ -336,7 +321,7 @@
 
 // Cancel should always return CANCELED from any starting state including
 // the IDLE state.
-TEST_F(FaceHidlTest, CancelTest) {
+TEST_P(FaceHidlTest, CancelTest) {
     Return<Status> ret = mService->cancel();
     // check that we were able to make an IPC request successfully
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
@@ -347,7 +332,7 @@
     EXPECT_EQ(FaceError::CANCELED, res.args->error);
 }
 
-TEST_F(FaceHidlTest, OnLockoutChangedTest) {
+TEST_P(FaceHidlTest, OnLockoutChangedTest) {
     // Update active user and ensure onLockoutChanged was called.
     Return<Status> ret = mService->setActiveUser(kUserId + 1, kFacedataDir);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
@@ -359,11 +344,7 @@
 
 }  // anonymous namespace
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(FaceHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    FaceHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, FaceHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index 76f9778..ac32c95 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -252,8 +252,7 @@
         // No need to use bytesPerPixel and bytesPerStride because we are using
         // an 1-D buffer and accressRegion.
         mMapperV4->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                        [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
-                            const auto& /*bytesPerStride*/) {
+                        [&](const auto& tmpError, const auto& tmpPtr) {
                             if (tmpError == MapperErrorV4::NONE) {
                                 ret = tmpPtr;
                             } else {
@@ -301,7 +300,13 @@
     }
 
     if (mMapperV4 != nullptr) {
-        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
+        // No device currently supports IMapper 4.0 so it is safe to just return an error code here.
+        //
+        // This will be supported by a combination of lock and BufferMetadata getters. We are going
+        // to refactor all the IAllocator/IMapper versioning code into a shared library. We will
+        // then add the IMapper 4.0 lockYCbCr support then.
+        ALOGE("%s: MapperV4 doesn't support lockYCbCr directly!", __FUNCTION__);
+        return {};
     }
 
     if (mMapperV3 != nullptr) {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 4bd8332..99ffeae 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -367,10 +367,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.radio.config</name>
-        <!--
-        See compatibility_matrix.4.xml on versioning of radio config HAL.
-        -->
-        <version>1.1</version>
+        <version>1.3</version>
         <interface>
             <name>IRadioConfig</name>
             <instance>default</instance>
diff --git a/current.txt b/current.txt
index d5082af..34621a5 100644
--- a/current.txt
+++ b/current.txt
@@ -604,7 +604,7 @@
 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel
 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-103cb87c5ed46851badac097f8d190da60f39b5ab32d60e2e93f64d3014ea75c android.hardware.neuralnetworks@1.3::types
+2d16429145dc1158bf3e45c7de86a39e461dec3ec00512c11a7e5249535a2e96 android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
 a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
@@ -614,4 +614,8 @@
 274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types
 c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio
 a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication
-260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse
\ No newline at end of file
+260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse
+55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
+b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
+742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
+7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
diff --git a/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
index 04d8710..495693c 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
@@ -34,7 +34,7 @@
      * For custom vendor types, the "name" field will be set to the name of the custom
      * @VendorStability vendor AIDL interface such as
      * "vendor.mycompanyname.graphics.common.Compression". The name of the vendor extension should
-     * contain the name of the company that owns the extension. Including the company
+     * contain the name of the owner of the extension. Including the company
      * name in the "name" field prevents type collisions between different vendors.
      */
     @utf8InCpp String name;
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index a0745ce..a8e1480 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -369,10 +369,7 @@
         accessRegion.top = accessRegionRect.top;
         accessRegion.width = accessRegionRect.width;
         accessRegion.height = accessRegionRect.height;
-        int32_t bytesPerPixel;
-        int32_t bytesPerStride;
-        return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel,
-                               &bytesPerStride);
+        return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
     } else if (mGralloc3) {
         IMapper3::Rect accessRegion;
         accessRegion.left = accessRegionRect.left;
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
index 138d700..35162a6 100644
--- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -93,17 +93,18 @@
     }
 
    protected:
-    void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
-        V2_1::CommandWriterBase::beginCommand(
-            static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
-    }
-
     void writeFloatColor(const IComposerClient::FloatColor& color) {
         writeFloat(color.r);
         writeFloat(color.g);
         writeFloat(color.b);
         writeFloat(color.a);
     }
+
+  private:
+    void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
+        V2_1::CommandWriterBase::beginCommand(
+                static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
 };
 
 // This class helps parse a command queue.  Note that all sizes/lengths are in
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index 11863fa..162915e 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -119,17 +119,18 @@
     }
 
    protected:
-    void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
-        V2_2::CommandWriterBase::beginCommand_2_2(
-            static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
-    }
-
     void writeBlob(uint32_t length, const unsigned char* blob) {
         memcpy(&mData[mDataWritten], blob, length);
         uint32_t numElements = length / 4;
         mDataWritten += numElements;
         mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0;
     }
+
+  private:
+    void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
+        V2_1::CommandWriterBase::beginCommand(
+                static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
 };
 
 // This class helps parse a command queue.  Note that all sizes/lengths are in
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index a541382..a1f07a4 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -199,16 +199,20 @@
      * outside of @p accessRegion is undefined, except that it must not cause
      * process termination.
      *
+     * This function can lock both single-planar and multi-planar formats. The caller
+     * should use get() to get information about the buffer they are locking.
+     * get() can be used to get information about the planes, offsets, stride,
+     * etc.
+     *
+     * This function must also work on buffers with
+     * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
+     * as with any other formats requested by multimedia codecs when they are
+     * configured with a flexible-YUV-compatible color format.
+     *
      * On success, @p data must be filled with a pointer to the locked buffer
      * memory. This address will represent the top-left corner of the entire
      * buffer, even if @p accessRegion does not begin at the top-left corner.
      *
-     * On success, bytesPerPixel must contain the number of bytes per pixel in
-     * the buffer. If the bytesPerPixel is unknown or variable, a value of -1
-     * should be returned. bytesPerStride must contain the bytes per stride of
-     * the buffer. If the bytesPerStride is unknown or variable, a value of -1
-     * should be returned.
-     *
      * The locked buffer must adhere to the format requested at allocation time
      * in the BufferDescriptorInfo.
      *
@@ -231,55 +235,13 @@
      *     - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
      *       that locking may succeed at a later time.
      * @return data CPU-accessible pointer to the buffer data.
-     * @return bytesPerPixel the number of bytes per pixel in the buffer
-     * @return bytesPerStride the number of bytes per stride of the buffer
      */
     lock(pointer buffer,
          uint64_t cpuUsage,
          Rect accessRegion,
          handle acquireFence)
             generates (Error error,
-                       pointer data,
-                       int32_t bytesPerPixel,
-                       int32_t bytesPerStride);
-
-    /**
-     * Locks a YCbCr buffer for the specified CPU usage.
-     *
-     * This is largely the same as lock(), except that instead of returning a
-     * pointer directly to the buffer data, it returns a `YCbCrLayout` struct
-     * describing how to access the data planes.
-     *
-     * This function must work on buffers with
-     * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
-     * as with any other formats requested by multimedia codecs when they are
-     * configured with a flexible-YUV-compatible color format.
-     *
-     * @param buffer Buffer to lock.
-     * @param cpuUsage CPU usage flags to request. See +ndk
-     *     libnativewindow#AHardwareBuffer_UsageFlags for possible values.
-     * @param accessRegion Portion of the buffer that the client intends to
-     *     access.
-     * @param acquireFence Handle containing a file descriptor referring to a
-     *     sync fence object, which will be signaled when it is safe for the
-     *     mapper to lock the buffer. @p acquireFence may be empty if it is
-     *     already safe to lock.
-     * @return error Error status of the call, which may be
-     *     - `NONE` upon success.
-     *     - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
-     *       function.
-     *     - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
-     *       is incompatible with the buffer.
-     *     - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
-     *       that locking may succeed at a later time.
-     * @return layout Data layout of the locked buffer.
-     */
-    lockYCbCr(pointer buffer,
-              uint64_t cpuUsage,
-              Rect accessRegion,
-              handle acquireFence)
-            generates (Error error,
-                       YCbCrLayout layout);
+                       pointer data);
 
     /**
      * Unlocks a buffer to indicate all CPU accesses to the buffer have
@@ -356,7 +318,7 @@
      * to read from a buffer, they have permission to read the buffer's metadata.
      *
      * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
-     * metadata. A process should finish writing to a buffer's metadata before sending
+     * metadata. A process should finish writing to a buffer's metadata before
      * sending the buffer to another process that will read or write to the buffer.
      * This exception is needed because sometimes userspace needs to read the
      * buffer's metadata before the buffer's contents are ready.
@@ -515,5 +477,43 @@
                                 MetadataType metadataType)
             generates (Error error,
                        vec<uint8_t> metadata);
+
+    struct MetadataTypeDescription {
+        MetadataType metadataType;
+        /**
+         * description should contain a string representation of the MetadataType.
+         *
+         * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
+         * that indicates when a buffer is decoded. It is set by the media HAL after
+         * a buffer is decoded. It is used by the display HAL for hardware
+         * synchronization".
+         *
+         * This field is required for any non-StandardMetadataTypes.
+         */
+        string description;
+        /**
+         * isGettable represents if the MetadataType can be get.
+         */
+        bool isGettable;
+        /**
+         * isSettable represents if the MetadataType can be set.
+         */
+        bool isSettable;
+    };
+
+    /**
+     * Lists all the MetadataTypes supported by IMapper as well as a description
+     * of each supported MetadataType. For StandardMetadataTypes, the description
+     * string can be left empty.
+     *
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *       resources.
+     * @return descriptions Vector of MetadataTypeDescriptions that represent the
+     *  MetadataTypes supported by the device.
+     */
+    listSupportedMetadataTypes()
+            generates (Error error, vec<MetadataTypeDescription> descriptions);
 };
 
diff --git a/graphics/mapper/4.0/types.hal b/graphics/mapper/4.0/types.hal
index 2fdfa65..00b6607 100644
--- a/graphics/mapper/4.0/types.hal
+++ b/graphics/mapper/4.0/types.hal
@@ -53,32 +53,3 @@
  */
 typedef vec<uint8_t> BufferDescriptor;
 
-/**
- * Structure for describing YCbCr formats for consumption by applications.
- * This is used with PixelFormat::YCBCR_*_888.
- *
- * Buffer chroma subsampling is defined in the format.
- * e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0.
- *
- * Buffers must have a 8 bit depth.
- *
- * y, cb, and cr point to the first byte of their respective planes.
- *
- * Stride describes the distance in bytes from the first value of one row of
- * the image to the first value of the next row. It includes the width of the
- * image plus padding.
- * yStride is the stride of the luma plane.
- * cStride is the stride of the chroma planes.
- *
- * chromaStep is the distance in bytes from one chroma pixel value to the
- * next. This is 2 bytes for semiplanar (because chroma values are interleaved
- * and each chroma value is one byte) and 1 for planar.
- */
-struct YCbCrLayout {
-    pointer y;
-    pointer cb;
-    pointer cr;
-    uint32_t yStride;
-    uint32_t cStride;
-    uint32_t chromaStep;
-};
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 531f311..8073e69 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -199,8 +199,7 @@
 }
 
 void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                    const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel,
-                    int32_t* outBytesPerStride) {
+                    const IMapper::Rect& accessRegion, int acquireFence) {
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
     NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -211,17 +210,11 @@
         acquireFenceHandle = h;
     }
 
-    *outBytesPerPixel = -1;
-    *outBytesPerStride = -1;
-
     void* data = nullptr;
     mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                  [&](const auto& tmpError, const auto& tmpData, int32_t tmpBytesPerPixel,
-                      int32_t tmpBytesPerStride) {
+                  [&](const auto& tmpError, const auto& tmpData) {
                       ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
                       data = tmpData;
-                      *outBytesPerPixel = tmpBytesPerPixel;
-                      *outBytesPerStride = tmpBytesPerStride;
                   });
 
     if (acquireFence >= 0) {
@@ -231,33 +224,6 @@
     return data;
 }
 
-YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                               const IMapper::Rect& accessRegion, int acquireFence) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
-    hidl_handle acquireFenceHandle;
-    if (acquireFence >= 0) {
-        auto h = native_handle_init(acquireFenceStorage, 1, 0);
-        h->data[0] = acquireFence;
-        acquireFenceHandle = h;
-    }
-
-    YCbCrLayout layout = {};
-    mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                       [&](const auto& tmpError, const auto& tmpLayout) {
-                           ASSERT_EQ(Error::NONE, tmpError)
-                                   << "failed to lockYCbCr buffer " << buffer;
-                           layout = tmpLayout;
-                       });
-
-    if (acquireFence >= 0) {
-        close(acquireFence);
-    }
-
-    return layout;
-}
-
 int Gralloc::unlock(const native_handle_t* bufferHandle) {
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index 28555fa..6251e66 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -70,10 +70,7 @@
     // 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* bufferHandle, uint64_t cpuUsage,
-               const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel,
-               int32_t* outBytesPerStride);
-    YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                          const IMapper::Rect& accessRegion, int acquireFence);
+               const IMapper::Rect& accessRegion, int acquireFence);
     int unlock(const native_handle_t* bufferHandle);
 
     bool validateBufferSize(const native_handle_t* bufferHandle,
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 1e8ec01..dd748db 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -20,6 +20,9 @@
 #include <thread>
 #include <vector>
 
+//#include <aidl/android/hardware/graphics/common/BlendMode.h>
+//#include <aidl/android/hardware/graphics/common/Compression.h>
+
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <gralloctypes/Gralloc4.h>
@@ -41,6 +44,7 @@
 using aidl::android::hardware::graphics::common::ExtendableType;
 using aidl::android::hardware::graphics::common::PlaneLayout;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::StandardMetadataType;
 
 using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
                                           const hidl_vec<uint8_t>& vec)>;
@@ -162,6 +166,27 @@
 
     std::unique_ptr<Gralloc> mGralloc;
     IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
+    static const std::set<StandardMetadataType> sRequiredMetadataTypes;
+};
+
+const std::set<StandardMetadataType> GraphicsMapperHidlTest::sRequiredMetadataTypes{
+        StandardMetadataType::BUFFER_ID,
+        StandardMetadataType::NAME,
+        StandardMetadataType::WIDTH,
+        StandardMetadataType::HEIGHT,
+        StandardMetadataType::LAYER_COUNT,
+        StandardMetadataType::PIXEL_FORMAT_REQUESTED,
+        StandardMetadataType::PIXEL_FORMAT_FOURCC,
+        StandardMetadataType::PIXEL_FORMAT_MODIFIER,
+        StandardMetadataType::USAGE,
+        StandardMetadataType::ALLOCATION_SIZE,
+        StandardMetadataType::PROTECTED_CONTENT,
+        StandardMetadataType::COMPRESSION,
+        StandardMetadataType::INTERLACED,
+        StandardMetadataType::CHROMA_SITING,
+        StandardMetadataType::PLANE_LAYOUTS,
+        StandardMetadataType::DATASPACE,
+        StandardMetadataType::BLEND_MODE,
 };
 
 /**
@@ -391,15 +416,8 @@
                                static_cast<int32_t>(info.height)};
     int fence = -1;
     uint8_t* data;
-    int32_t bytesPerPixel = -1;
-    int32_t bytesPerStride = -1;
     ASSERT_NO_FATAL_FAILURE(
-            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence,
-                                                        &bytesPerPixel, &bytesPerStride)));
-
-    // Valid return values are -1 for unsupported or the number bytes for supported which is >=0
-    EXPECT_GT(bytesPerPixel, -1);
-    EXPECT_GT(bytesPerStride, -1);
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
 
     // RGBA_8888
     size_t strideInBytes = stride * 4;
@@ -412,13 +430,9 @@
 
     ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
 
-    bytesPerPixel = -1;
-    bytesPerStride = -1;
-
     // lock again for reading
     ASSERT_NO_FATAL_FAILURE(
-            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence,
-                                                        &bytesPerPixel, &bytesPerStride)));
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
     for (uint32_t y = 0; y < info.height; y++) {
         for (size_t i = 0; i < writeInBytes; i++) {
             EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
@@ -426,69 +440,6 @@
         data += strideInBytes;
     }
 
-    EXPECT_GT(bytesPerPixel, -1);
-    EXPECT_GT(bytesPerStride, -1);
-
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
-    if (fence >= 0) {
-        close(fence);
-    }
-}
-
-/**
- * Test IMapper::lockYCbCr.  This locks a YV12 buffer, and makes sure we can
- * write to and read from it.
- */
-TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
-    auto info = mDummyDescriptorInfo;
-    info.format = PixelFormat::YV12;
-
-    const native_handle_t* bufferHandle;
-    uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
-
-    // 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;
-    YCbCrLayout layout;
-    ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
-
-    auto yData = static_cast<uint8_t*>(layout.y);
-    auto cbData = static_cast<uint8_t*>(layout.cb);
-    auto crData = static_cast<uint8_t*>(layout.cr);
-    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);
-
-            yData[layout.yStride * y + x] = val;
-            if (y % 2 == 0 && x % 2 == 0) {
-                cbData[layout.cStride * y / 2 + x / 2] = val;
-                crData[layout.cStride * y / 2 + x / 2] = val;
-            }
-        }
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
-
-    // lock again for reading
-    ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
-
-    yData = static_cast<uint8_t*>(layout.y);
-    cbData = static_cast<uint8_t*>(layout.cb);
-    crData = static_cast<uint8_t*>(layout.cr);
-    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, yData[layout.yStride * y + x]);
-            if (y % 2 == 0 && x % 2 == 0) {
-                EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]);
-                EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]);
-            }
-        }
-    }
-
     ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
     if (fence >= 0) {
         close(fence);
@@ -518,8 +469,7 @@
 
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
     mGralloc->getMapper()->lock(buffer, info.usage, accessRegion, acquireFenceHandle,
-                                [&](const auto& tmpError, const auto& /*tmpData*/,
-                                    int32_t /*tmpBytesPerPixel*/, int32_t /*tmpBytesPerStride*/) {
+                                [&](const auto& tmpError, const auto& /*tmpData*/) {
                                     EXPECT_EQ(Error::BAD_VALUE, tmpError)
                                             << "locking with a bad access region should fail";
                                 });
@@ -1591,6 +1541,54 @@
     ASSERT_EQ(0, vec.size());
 }
 
+/**
+ * Test IMapper::listSupportedMetadataTypes()
+ */
+TEST_F(GraphicsMapperHidlTest, ListSupportedMetadataTypes) {
+    hidl_vec<IMapper::MetadataTypeDescription> descriptions;
+    mGralloc->getMapper()->listSupportedMetadataTypes(
+            [&](const auto& tmpError, const auto& tmpDescriptions) {
+                ASSERT_EQ(Error::NONE, tmpError);
+                descriptions = tmpDescriptions;
+            });
+
+    std::set<StandardMetadataType> foundMetadataTypes;
+
+    std::set<StandardMetadataType> notSettableMetadataTypes{
+            StandardMetadataType::BUFFER_ID,   StandardMetadataType::NAME,
+            StandardMetadataType::WIDTH,       StandardMetadataType::HEIGHT,
+            StandardMetadataType::LAYER_COUNT, StandardMetadataType::PIXEL_FORMAT_REQUESTED,
+            StandardMetadataType::USAGE};
+
+    ASSERT_LE(sRequiredMetadataTypes.size(), descriptions.size());
+
+    for (const auto& description : descriptions) {
+        const auto& metadataType = description.metadataType;
+
+        if (!gralloc4::isStandardMetadataType(metadataType)) {
+            EXPECT_GT(0, description.description.size());
+            continue;
+        }
+
+        StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType);
+
+        if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) {
+            continue;
+        }
+
+        ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end());
+        foundMetadataTypes.insert(type);
+
+        ASSERT_TRUE(description.isGettable);
+
+        if (notSettableMetadataTypes.find(type) != notSettableMetadataTypes.end()) {
+            ASSERT_FALSE(description.isSettable);
+        }
+    }
+
+    ASSERT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
+}
+
 }  // namespace
 }  // namespace vts
 }  // namespace V4_0
diff --git a/health/2.0/default/healthd_common_adapter.cpp b/health/2.0/default/healthd_common_adapter.cpp
index 8fc689d..0b5d869 100644
--- a/health/2.0/default/healthd_common_adapter.cpp
+++ b/health/2.0/default/healthd_common_adapter.cpp
@@ -49,11 +49,14 @@
 static std::unique_ptr<HealthLoopAdapter> health_loop;
 
 int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+    if (!health_loop) return -1;
+
     auto wrapped_handler = [handler](auto*, uint32_t epevents) { handler(epevents); };
     return health_loop->RegisterEvent(fd, wrapped_handler, wakeup);
 }
 
 void healthd_battery_update_internal(bool charger_online) {
+    if (!health_loop) return;
     health_loop->AdjustWakealarmPeriods(charger_online);
 }
 
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index db86bf6..3551d57 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -149,6 +149,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -210,7 +211,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     AVERAGE_POOL_2D = @1.2::OperationType:AVERAGE_POOL_2D,
@@ -954,6 +956,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4.
      *
@@ -965,6 +968,8 @@
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 256 and the zeroPoint must be 0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the scale must be 1.f / 256 and the zeroPoint must be -128.
      */
     LOGISTIC = @1.2::OperationType:LOGISTIC,
 
@@ -1259,6 +1264,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -1320,7 +1326,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     MAX_POOL_2D = @1.2::OperationType:MAX_POOL_2D,
@@ -1380,6 +1387,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4.
      *
@@ -1389,7 +1397,8 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     RELU = @1.2::OperationType:RELU,
@@ -1405,6 +1414,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4.
      *
@@ -1414,7 +1424,8 @@
      *
      * Outputs:
      * * 0: The output tensor of the same shape as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     RELU1 = @1.2::OperationType:RELU1,
@@ -1430,6 +1441,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4.
      *
@@ -1439,7 +1451,8 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     RELU6 = @1.2::OperationType:RELU6,
@@ -1760,6 +1773,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4.
      *
@@ -1771,6 +1785,8 @@
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 128 and the zeroPoint must be 128.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 0.
      */
     TANH = @1.2::OperationType:TANH,
 
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
new file mode 100644
index 0000000..88de666
--- /dev/null
+++ b/radio/config/1.3/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.radio.config@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IRadioConfig.hal",
+        "IRadioConfigIndication.hal",
+        "IRadioConfigResponse.hal",
+    ],
+    interfaces: [
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal
new file mode 100644
index 0000000..a0ce6e0
--- /dev/null
+++ b/radio/config/1.3/IRadioConfig.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.config@1.3;
+
+import @1.1::IRadioConfig;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio for the purpose of
+ * radio configuration, and it is not associated with any specific modem or slot.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ */
+interface IRadioConfig extends @1.1::IRadioConfig {
+
+};
diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/radio/config/1.3/IRadioConfigIndication.hal
new file mode 100644
index 0000000..9ef496c
--- /dev/null
+++ b/radio/config/1.3/IRadioConfigIndication.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.config@1.3;
+
+import @1.2::IRadioConfigIndication;
+
+/**
+ * Interface declaring unsolicited radio config indications.
+ */
+interface IRadioConfigIndication extends @1.2::IRadioConfigIndication {
+
+};
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
new file mode 100644
index 0000000..9c4c971
--- /dev/null
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.config@1.3;
+
+import @1.2::IRadioConfigResponse;
+
+/**
+ * Interface declaring response functions to solicited radio config requests.
+ */
+interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
+
+};
diff --git a/radio/config/1.3/default/Android.bp b/radio/config/1.3/default/Android.bp
new file mode 100644
index 0000000..163c5c5
--- /dev/null
+++ b/radio/config/1.3/default/Android.bp
@@ -0,0 +1,28 @@
+cc_binary {
+    name: "android.hardware.radio.config@1.3-service",
+    init_rc: ["android.hardware.radio.config@1.3-service.rc"],
+    relative_install_path: "hw",
+    vintf_fragments: ["radio-config-default.xml"],
+    vendor: true,
+    srcs: [
+        "RadioConfig.cpp",
+        "RadioConfigIndication.cpp",
+        "RadioConfigResponse.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio.config@1.3",
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.4",
+        "android.hardware.radio@1.5",
+    ],
+}
diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp
new file mode 100644
index 0000000..c28119c
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfig.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "RadioConfig.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
+Return<void> RadioConfig::setResponseFunctions(
+        const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+        const sp<V1_0::IRadioConfigIndication>& radioConfigIndication) {
+    mRadioConfigResponse = radioConfigResponse;
+    mRadioConfigIndication = radioConfigIndication;
+
+    mRadioConfigResponseV1_3 =
+            V1_3::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_3 =
+            V1_3::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_3 == nullptr || mRadioConfigIndicationV1_3 == nullptr) {
+        mRadioConfigResponseV1_3 = nullptr;
+        mRadioConfigIndicationV1_3 = nullptr;
+    }
+
+    mRadioConfigResponseV1_2 =
+            V1_2::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_2 =
+            V1_2::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_2 == nullptr || mRadioConfigIndicationV1_2 == nullptr) {
+        mRadioConfigResponseV1_2 = nullptr;
+        mRadioConfigIndicationV1_2 = nullptr;
+    }
+
+    mRadioConfigResponseV1_1 =
+            V1_1::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_1 =
+            V1_1::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_1 == nullptr || mRadioConfigIndicationV1_1 == nullptr) {
+        mRadioConfigResponseV1_1 = nullptr;
+        mRadioConfigIndicationV1_1 = nullptr;
+    }
+
+    return Void();
+}
+
+Return<void> RadioConfig::getSimSlotsStatus(int32_t /* serial */) {
+    hidl_vec<V1_0::SimSlotStatus> slotStatus;
+    RadioResponseInfo info;
+    mRadioConfigResponse->getSimSlotsStatusResponse(info, slotStatus);
+    return Void();
+}
+
+Return<void> RadioConfig::setSimSlotsMapping(int32_t /* serial */,
+                                             const hidl_vec<uint32_t>& /* slotMap */) {
+    RadioResponseInfo info;
+    mRadioConfigResponse->setSimSlotsMappingResponse(info);
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
+Return<void> RadioConfig::getPhoneCapability(int32_t /* serial */) {
+    V1_1::PhoneCapability phoneCapability;
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->getPhoneCapabilityResponse(info, phoneCapability);
+    return Void();
+}
+
+Return<void> RadioConfig::setPreferredDataModem(int32_t /* serial */, uint8_t /* modemId */) {
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->setPreferredDataModemResponse(info);
+    return Void();
+}
+
+Return<void> RadioConfig::setModemsConfig(int32_t /* serial */,
+                                          const V1_1::ModemsConfig& /* modemsConfig */) {
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->setModemsConfigResponse(info);
+    return Void();
+}
+
+Return<void> RadioConfig::getModemsConfig(int32_t /* serial */) {
+    V1_1::ModemsConfig modemsConfig;
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->getModemsConfigResponse(info, modemsConfig);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h
new file mode 100644
index 0000000..00585e6
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfig.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_RADIO_CONFIG_V1_3_RADIOCONFIG_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::config;
+
+using ::android::sp;
+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;
+
+struct RadioConfig : public V1_3::IRadioConfig {
+    sp<V1_0::IRadioConfigResponse> mRadioConfigResponse;
+    sp<V1_0::IRadioConfigIndication> mRadioConfigIndication;
+    sp<V1_1::IRadioConfigResponse> mRadioConfigResponseV1_1;
+    sp<V1_1::IRadioConfigIndication> mRadioConfigIndicationV1_1;
+    sp<V1_2::IRadioConfigResponse> mRadioConfigResponseV1_2;
+    sp<V1_2::IRadioConfigIndication> mRadioConfigIndicationV1_2;
+    sp<V1_3::IRadioConfigResponse> mRadioConfigResponseV1_3;
+    sp<V1_3::IRadioConfigIndication> mRadioConfigIndicationV1_3;
+
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
+    Return<void> setResponseFunctions(
+            const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+            const sp<V1_0::IRadioConfigIndication>& radioConfigIndication);
+    Return<void> getSimSlotsStatus(int32_t serial);
+    Return<void> setSimSlotsMapping(int32_t serial, const hidl_vec<uint32_t>& slotMap);
+
+    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
+    Return<void> getPhoneCapability(int32_t serial);
+    Return<void> setPreferredDataModem(int32_t serial, uint8_t modemId);
+    Return<void> setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig);
+    Return<void> getModemsConfig(int32_t serial);
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp
new file mode 100644
index 0000000..eb77a48
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigIndication.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "RadioConfigIndication.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config::V1_0;
+using namespace ::android::hardware::radio::config::V1_2;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
+Return<void> RadioConfigIndication::simSlotsStatusChanged(
+        RadioIndicationType /* type */, const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
+Return<void> RadioConfigIndication::simSlotsStatusChanged_1_2(
+        RadioIndicationType /* type */, const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h
new file mode 100644
index 0000000..3697492
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigIndication.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config;
+
+using ::android::sp;
+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;
+
+struct RadioConfigIndication : public IRadioConfigIndication {
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
+    Return<void> simSlotsStatusChanged(RadioIndicationType type,
+                                       const hidl_vec<V1_0::SimSlotStatus>& slotStatus) override;
+
+    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
+    Return<void> simSlotsStatusChanged_1_2(
+            RadioIndicationType type, const hidl_vec<V1_2::SimSlotStatus>& slotStatus) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp
new file mode 100644
index 0000000..48e81da
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigResponse.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "RadioConfigResponse.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config::V1_0;
+using namespace ::android::hardware::radio::config::V1_1;
+using namespace ::android::hardware::radio::config::V1_2;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */,
+        const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& /* info */, const V1_1::PhoneCapability& /* phoneCapability */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(
+        const RadioResponseInfo& /* info */, const V1_1::ModemsConfig& /* modemsConfig */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
+        const RadioResponseInfo& /* info */,
+        const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h
new file mode 100644
index 0000000..0f0033f
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigResponse.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::sp;
+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;
+
+struct RadioConfigResponse : public IRadioConfigResponse {
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
+    Return<void> getSimSlotsStatusResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus)
+            override;
+    Return<void> setSimSlotsMappingResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+
+    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
+    Return<void> getPhoneCapabilityResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability)
+            override;
+    Return<void> setPreferredDataModemResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+    Return<void> setModemsConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+    Return<void> getModemsConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override;
+
+    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
+    Return<void> getSimSlotsStatusResponse_1_2(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus)
+            override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
diff --git a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
new file mode 100644
index 0000000..6df9b52
--- /dev/null
+++ b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
@@ -0,0 +1,7 @@
+service vendor.radio-config-hal-1-3 /vendor/bin/hw/android.hardware.radio.config@1.3-service
+    interface android.hardware.radio.config@1.0::IRadioConfig default
+    interface android.hardware.radio.config@1.1::IRadioConfig default
+    interface android.hardware.radio.config@1.3::IRadioConfig default
+    class hal
+    user system
+    group system
diff --git a/radio/config/1.3/default/radio-config-default.xml b/radio/config/1.3/default/radio-config-default.xml
new file mode 100644
index 0000000..72f363e
--- /dev/null
+++ b/radio/config/1.3/default/radio-config-default.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.radio.config</name>
+        <transport>hwbinder</transport>
+        <version>1.3</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/radio/config/1.3/default/service.cpp b/radio/config/1.3/default/service.cpp
new file mode 100644
index 0000000..b1e6736
--- /dev/null
+++ b/radio/config/1.3/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.radio.config@1.3-service"
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "RadioConfig.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::radio::config::V1_3::IRadioConfig;
+using android::hardware::radio::config::V1_3::implementation::RadioConfig;
+
+int main() {
+    configureRpcThreadpool(1, true);
+    sp<IRadioConfig> radioConfig = new RadioConfig;
+    const status_t status = radioConfig->registerAsService();
+    ALOGW_IF(status != OK, "Could not register IRadioConfig 1.3");
+    ALOGD("Default service is ready.");
+
+    joinRpcThreadpool();
+    return 1;
+}
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
new file mode 100644
index 0000000..866002a
--- /dev/null
+++ b/radio/config/1.3/types.hal
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.config@1.3;
diff --git a/radio/config/1.3/vts/functional/Android.bp b/radio/config/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..6b28faf
--- /dev/null
+++ b/radio/config/1.3/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalRadioConfigV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "radio_config_hidl_hal_api.cpp",
+        "radio_config_hidl_hal_test.cpp",
+        "radio_config_response.cpp",
+        "VtsHalRadioConfigV1_3TargetTest.cpp",
+    ],
+    static_libs: [
+        "RadioVtsTestUtilBase",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio.config@1.3",
+    ],
+    header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests", "vts-core"],
+}
diff --git a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
new file mode 100644
index 0000000..3bacacf
--- /dev/null
+++ b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioConfigHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                ::android::hardware::radio::config::V1_3::IRadioConfig::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
new file mode 100644
index 0000000..07e9ede
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
new file mode 100644
index 0000000..dbb4bf4
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+void RadioConfigHidlTest::SetUp() {
+    radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam());
+    ASSERT_NE(nullptr, radioConfig.get());
+
+    radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
+    ASSERT_NE(nullptr, radioConfigRsp.get());
+
+    count_ = 0;
+
+    radioConfig->setResponseFunctions(radioConfigRsp, nullptr);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioConfigHidlTest::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx_);
+    if (serial == receivedSerial) {
+        count_++;
+        cv_.notify_one();
+    }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioConfigHidlTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count_--;
+    return status;
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
new file mode 100644
index 0000000..9b78c04
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.3/types.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::config::V1_1;
+using namespace ::android::hardware::radio::config::V1_2;
+using namespace ::android::hardware::radio::config::V1_3;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+using ::android::hardware::radio::V1_0::RadioResponseType;
+
+#define TIMEOUT_PERIOD 75
+
+class RadioConfigHidlTest;
+
+/* Callback class for radio config response */
+class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse {
+  protected:
+    RadioConfigHidlTest& parent;
+
+  public:
+    RadioResponseInfo rspInfo;
+    PhoneCapability phoneCap;
+
+    RadioConfigResponse(RadioConfigHidlTest& parent);
+    virtual ~RadioConfigResponse() = default;
+
+    /* 1.0 Api */
+    Return<void> getSimSlotsStatusResponse(
+            const RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus);
+
+    Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
+
+    /* 1.1 Api */
+    Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+                                            const PhoneCapability& phoneCapability);
+
+    Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
+
+    Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+                                         const ModemsConfig& mConfig);
+
+    Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
+
+    /* 1.2 Api */
+    Return<void> getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info,
+                                               const hidl_vec<SimSlotStatus>& slotStatus);
+};
+
+/* Callback class for radio config indication */
+class RadioConfigIndication
+    : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication {
+  protected:
+    RadioConfigHidlTest& parent;
+
+  public:
+    RadioConfigIndication(RadioConfigHidlTest& parent);
+    virtual ~RadioConfigIndication() = default;
+
+    /* 1.2 Api */
+    Return<void> simSlotsStatusChanged_1_2(
+            ::android::hardware::radio::V1_0::RadioIndicationType type,
+            const hidl_vec<SimSlotStatus>& slotStatus);
+};
+
+// The main test class for Radio config HIDL.
+class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_;
+
+  public:
+    virtual void SetUp() override;
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    void updateSimCardStatus();
+
+    /* Serial number for radio request */
+    int serial;
+
+    /* radio config service handle */
+    sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig;
+
+    /* radio config response handle */
+    sp<RadioConfigResponse> radioConfigRsp;
+};
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
new file mode 100644
index 0000000..1ca960e
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_config_hidl_hal_utils.h>
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+
+// SimSlotStatus slotStatus;
+
+RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
+
+/* 1.0 Apis */
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& info, const PhoneCapability& phoneCapability) {
+    rspInfo = info;
+    phoneCap = phoneCapability;
+    parent.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */,
+                                                          const ModemsConfig& /* mConfig */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
+        const RadioResponseInfo& /* info */,
+        const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) {
+    return Void();
+}
\ No newline at end of file
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
index c13eaf2..811c455 100644
--- a/sensors/2.0/multihal/Android.bp
+++ b/sensors/2.0/multihal/Android.bp
@@ -43,10 +43,10 @@
     srcs: [
         "service.cpp",
         "HalProxy.cpp",
-        "ScopedWakelock.cpp",
     ],
     init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
     vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
+    shared_libs: ["android.hardware.sensors@2.0-ScopedWakelock"]
 }
 
 cc_library_headers {
@@ -55,19 +55,40 @@
     export_include_dirs: ["include"],
 }
 
+cc_library_shared {
+    name: "android.hardware.sensors@2.0-ScopedWakelock",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.0-multihal-defaults",
+    ],
+    srcs: [
+        "ScopedWakelock.cpp",
+    ],
+    vendor_available: true,
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-multihal.header"
+    ]
+}
+
 // The below targets should only be used for testing.
 cc_test_library {
     name: "android.hardware.sensors@2.0-HalProxy",
-    defaults: ["android.hardware.sensors@2.0-multihal-defaults"],
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.0-multihal-defaults",
+    ],
     vendor_available: true,
     srcs: [
         "HalProxy.cpp",
-        "ScopedWakelock.cpp",
     ],
     export_header_lib_headers: [
         "android.hardware.sensors@2.0-multihal.header",
     ],
+    export_shared_lib_headers: [
+	"android.hardware.sensors@2.0-ScopedWakelock",
+    ],
     shared_libs: [
         "libutils",
+        "android.hardware.sensors@2.0-ScopedWakelock",
     ],
 }
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
index e7f9499..1637312 100644
--- a/sensors/2.0/multihal/tests/Android.bp
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -25,6 +25,7 @@
     shared_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
+	"android.hardware.sensors@2.0-ScopedWakelock",
         "libcutils",
         "libfmq",
         "libhardware",
@@ -83,6 +84,7 @@
     shared_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.0-ScopedWakelock",
         "libbase",
         "libcutils",
         "libfmq",
diff --git a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
index f6f5537..015a345 100644
--- a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
+++ b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
@@ -20,9 +20,9 @@
 #include <binder/IServiceManager.h>
 #include <gtest/gtest.h>
 
+using android::checked_interface_cast;
 using android::IBinder;
 using android::IInterface;
-using android::interface_cast;
 using android::OK;
 using android::sp;
 using android::waitForVintfService;
@@ -44,7 +44,7 @@
     // getting the extension
     sp<IBinder> ext;
     ASSERT_EQ(OK, IInterface::asBinder(vib)->getExtension(&ext));
-    sp<ICustomVibrator> cvib = interface_cast<ICustomVibrator>(ext);
+    sp<ICustomVibrator> cvib = checked_interface_cast<ICustomVibrator>(ext);
     ASSERT_NE(nullptr, cvib.get());
 
     // calling extension method
diff --git a/tests/memory/2.0/Android.bp b/tests/memory/2.0/Android.bp
new file mode 100644
index 0000000..5166652
--- /dev/null
+++ b/tests/memory/2.0/Android.bp
@@ -0,0 +1,12 @@
+hidl_interface {
+    name: "android.hardware.tests.memory@2.0",
+    root: "android.hardware",
+    srcs: [
+        "IMemoryInterface.hal",
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/tests/memory/2.0/IMemoryInterface.hal b/tests/memory/2.0/IMemoryInterface.hal
new file mode 100644
index 0000000..2c824bf
--- /dev/null
+++ b/tests/memory/2.0/IMemoryInterface.hal
@@ -0,0 +1,12 @@
+package android.hardware.tests.memory@2.0;
+
+interface IMemoryInterface {
+    // Flips all the bits in the given memory buffer.
+    bitwiseNot(memory mem);
+    // Returns a read-only buffer of size 8, containing the bytes 0..7.
+    getTestMem() generates(memory mem);
+    // Given two memory regions of the same size, returns two memory fields of
+    // equal size, the first contains the byte-wise sum and the other the byte-
+    // wise difference.
+    getSumDiff(TwoMemory in) generates(TwoMemory out);
+};
diff --git a/tests/memory/2.0/types.hal b/tests/memory/2.0/types.hal
new file mode 100644
index 0000000..9ec357b
--- /dev/null
+++ b/tests/memory/2.0/types.hal
@@ -0,0 +1,6 @@
+package android.hardware.tests.memory@2.0;
+
+struct TwoMemory {
+    memory mem1;
+    memory mem2;
+};
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index cd5439f..e26041a 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -5,5 +5,11 @@
         "android/hardware/vibrator/*.aidl",
     ],
     stability: "vintf",
+    backend: {
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
 }
-
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
new file mode 100644
index 0000000..84556b5
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator;
+
+import android.hardware.vibrator.CompositePrimitive;
+
+@VintfStability
+parcelable CompositeEffect {
+    /* Period of silence preceding primitive. */
+    int delayMs;
+    CompositePrimitive primitive;
+    /* 0.0 (exclusive) - 1.0 (inclusive) */
+    float scale;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
new file mode 100644
index 0000000..2a9d0be
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+@Backing(type="int")
+enum CompositePrimitive {
+    NOOP,
+    CLICK,
+    THUD,
+    SPIN,
+    QUICK_RISE,
+    SLOW_RISE,
+    QUICK_FALL,
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index 8c4fd05..ebf5faa 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -19,6 +19,8 @@
 import android.hardware.vibrator.IVibratorCallback;
 import android.hardware.vibrator.Effect;
 import android.hardware.vibrator.EffectStrength;
+import android.hardware.vibrator.CompositeEffect;
+import android.hardware.vibrator.CompositePrimitive;
 
 @VintfStability
 interface IVibrator {
@@ -42,6 +44,10 @@
      * Whether setAmplitude is supported (when external control is enabled)
      */
     const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 1 << 4;
+    /**
+     * Whether compose is supported.
+     */
+    const int CAP_COMPOSE_EFFECTS = 1 << 5;
 
     /**
      * Determine capabilities of the vibrator HAL (CAP_* mask)
@@ -107,11 +113,10 @@
      * CAP_EXTERNAL_AMPLITUDE_CONTROL.
      *
      * @param amplitude The unitless force setting. Note that this number must
-     *                  be between 1 and 255, inclusive. If the motor does not
-     *                  have exactly 255 steps, it must do it's best to map it
-     *                  onto the number of steps it does have.
+     *                  be between 0.0 (exclusive) and 1.0 (inclusive). It must
+     *                  do it's best to map it onto the number of steps it does have.
      */
-    void setAmplitude(in int amplitude);
+    void setAmplitude(in float amplitude);
 
     /**
      * Enables/disables control override of vibrator to audio.
@@ -128,4 +133,36 @@
      * @param enabled Whether external control should be enabled or disabled.
      */
     void setExternalControl(in boolean enabled);
+
+    /**
+     * Retrieve composition delay limit.
+     *
+     * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+     *
+     * @return Maximum delay for a single CompositeEffect[] entry.
+     */
+    int getCompositionDelayMax();
+
+    /**
+     * Retrieve composition size limit.
+     *
+     * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+     *
+     * @return Maximum number of entries in CompositeEffect[].
+     * @param maxDelayMs Maximum delay for a single CompositeEffect[] entry.
+     */
+    int getCompositionSizeMax();
+
+    /**
+     * Fire off a string of effect primitives, combined to perform richer effects.
+     *
+     * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off.
+     *
+     * @param composite Array of composition parameters.
+     */
+    void compose(in CompositeEffect[] composite, in IVibratorCallback callback);
+
 }
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 09cd234..a77c49a 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -24,11 +24,14 @@
 namespace hardware {
 namespace vibrator {
 
+static constexpr int32_t kComposeDelayMaxMs = 1000;
+static constexpr int32_t kComposeSizeMax = 256;
+
 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
     LOG(INFO) << "Vibrator reporting capabilities";
     *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
                     IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
-                    IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL;
+                    IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -84,9 +87,9 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Vibrator::setAmplitude(int32_t amplitude) {
+ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
     LOG(INFO) << "Vibrator set amplitude: " << amplitude;
-    if (amplitude <= 0 || amplitude > 255) {
+    if (amplitude <= 0.0f || amplitude > 1.0f) {
         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
     }
     return ndk::ScopedAStatus::ok();
@@ -97,6 +100,55 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs) {
+    *maxDelayMs = kComposeDelayMaxMs;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) {
+    *maxSize = kComposeSizeMax;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
+                                     const std::shared_ptr<IVibratorCallback>& callback) {
+    if (composite.size() > kComposeSizeMax) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    for (auto& e : composite) {
+        if (e.delayMs > kComposeDelayMaxMs) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.scale <= 0.0f || e.scale > 1.0f) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.primitive < CompositePrimitive::NOOP ||
+            e.primitive > CompositePrimitive::QUICK_FALL) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        }
+    }
+
+    std::thread([=] {
+        LOG(INFO) << "Starting compose on another thread";
+
+        for (auto& e : composite) {
+            if (e.delayMs) {
+                usleep(e.delayMs * 1000);
+            }
+            LOG(INFO) << "triggering primitive " << static_cast<int>(e.primitive) << " @ scale "
+                      << e.scale;
+        }
+
+        if (callback != nullptr) {
+            LOG(INFO) << "Notifying perform complete";
+            callback->onComplete();
+        }
+    }).detach();
+
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 14e7292..817ec80 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -32,8 +32,12 @@
                                const std::shared_ptr<IVibratorCallback>& callback,
                                int32_t* _aidl_return) override;
     ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
-    ndk::ScopedAStatus setAmplitude(int32_t amplitude) override;
+    ndk::ScopedAStatus setAmplitude(float amplitude) override;
     ndk::ScopedAStatus setExternalControl(bool enabled) override;
+    ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
+    ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
+    ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
+                               const std::shared_ptr<IVibratorCallback>& callback) override;
 };
 
 }  // namespace vibrator
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index b6aa9e2..5c6120b 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -28,6 +28,8 @@
 using android::String16;
 using android::binder::Status;
 using android::hardware::vibrator::BnVibratorCallback;
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
 using android::hardware::vibrator::IVibrator;
@@ -55,6 +57,20 @@
         static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.back()) + 1),
 };
 
+// TODO(b/143992652): autogenerate
+const std::vector<CompositePrimitive> kCompositePrimitives = {
+        CompositePrimitive::NOOP,       CompositePrimitive::CLICK,
+        CompositePrimitive::THUD,       CompositePrimitive::SPIN,
+        CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
+        CompositePrimitive::QUICK_FALL,
+};
+// TODO(b/143992652): autogenerate
+
+const std::vector<CompositePrimitive> kInvalidPrimitives = {
+        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
+        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
+};
+
 class CompletionCallback : public BnVibratorCallback {
   public:
     CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
@@ -201,11 +217,11 @@
 
 TEST_P(VibratorAidl, ChangeVibrationAmplitude) {
     if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
-        EXPECT_TRUE(vibrator->setAmplitude(1).isOk());
+        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.1f).exceptionCode());
         EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
-        EXPECT_TRUE(vibrator->setAmplitude(128).isOk());
+        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.5f).exceptionCode());
         sleep(1);
-        EXPECT_TRUE(vibrator->setAmplitude(255).isOk());
+        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
         sleep(1);
     }
 }
@@ -214,7 +230,7 @@
     if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
         EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode());
         EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(256).exceptionCode());
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(1.1).exceptionCode());
     }
 }
 
@@ -240,7 +256,7 @@
     if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
         EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
 
-        Status amplitudeStatus = vibrator->setAmplitude(128);
+        Status amplitudeStatus = vibrator->setAmplitude(0.5);
         if (supportsExternalAmplitudeControl) {
             EXPECT_TRUE(amplitudeStatus.isOk());
         } else {
@@ -259,6 +275,102 @@
     }
 }
 
+TEST_P(VibratorAidl, ComposeValidPrimitives) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        int32_t maxDelay, maxSize;
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+
+        std::vector<CompositeEffect> composite;
+
+        for (auto primitive : kCompositePrimitives) {
+            CompositeEffect effect;
+
+            effect.delayMs = std::rand() % (maxDelay + 1);
+            effect.primitive = primitive;
+            effect.scale = static_cast<float>(std::rand()) / RAND_MAX ?: 1.0f;
+            composite.emplace_back(effect);
+
+            if (composite.size() == maxSize) {
+                EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+                composite.clear();
+                vibrator->off();
+            }
+        }
+
+        if (composite.size() != 0) {
+            EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+            vibrator->off();
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        for (auto primitive : kInvalidPrimitives) {
+            std::vector<CompositeEffect> composite(1);
+
+            for (auto& effect : composite) {
+                effect.delayMs = 0;
+                effect.primitive = primitive;
+                effect.scale = 1.0f;
+            }
+            EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+                      vibrator->compose(composite, nullptr).exceptionCode());
+            vibrator->off();
+        }
+    }
+}
+
+TEST_P(VibratorAidl, CompseDelayBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        int32_t maxDelay;
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
+
+        std::vector<CompositeEffect> composite(1);
+        CompositeEffect effect;
+
+        effect.delayMs = 1;
+        effect.primitive = CompositePrimitive::CLICK;
+        effect.scale = 1.0f;
+
+        std::fill(composite.begin(), composite.end(), effect);
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.delayMs = maxDelay + 1;
+
+        std::fill(composite.begin(), composite.end(), effect);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, CompseSizeBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        int32_t maxSize;
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+
+        std::vector<CompositeEffect> composite(maxSize);
+        CompositeEffect effect;
+
+        effect.delayMs = 1;
+        effect.primitive = CompositePrimitive::CLICK;
+        effect.scale = 1.0f;
+
+        std::fill(composite.begin(), composite.end(), effect);
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        composite.emplace_back(effect);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
 INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)),
                          android::PrintInstanceNameToString);