Snap for 6948038 from a3fdef4e60d9e2692e46c3f8a97eedf1fbfe4aa7 to rvc-platform-release

Change-Id: Iedc7ff97728db8867b143ce07ad2172513e521b3
diff --git a/audio/Android.bp b/audio/Android.bp
index 4905fe5..27dfbf8 100644
--- a/audio/Android.bp
+++ b/audio/Android.bp
@@ -13,9 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_shared {
-    name: "android.hardware.audio@6.0-impl.ranchu",
+cc_binary {
+    name: "android.hardware.audio.service.ranchu",
     vendor: true,
+    init_rc: ["android.hardware.audio.service.ranchu.rc"],
     vintf_fragments: ["android.hardware.audio@6.0-impl.ranchu.xml"],
     relative_install_path: "hw",
     defaults: ["hidl_defaults"],
@@ -27,6 +28,8 @@
         "stream_in.cpp",
         "stream_out.cpp",
         "io_thread.cpp",
+        "device_port_source.cpp",
+        "device_port_sink.cpp",
         "talsa.cpp",
         "util.cpp",
     ],
@@ -34,7 +37,9 @@
         "android.hardware.audio@6.0",
         "android.hardware.audio.common@6.0",
         "android.hardware.audio.common@6.0-util",
+        "libaudioutils",
         "libbase",
+        "libbinder",
         "libcutils",
         "libhidlbase",
         "liblog",
@@ -47,6 +52,13 @@
         "libaudio_system_headers",
     ],
     cflags: [
-        "-DLOG_TAG=\"android.hardware.audio@6.0-impl.ranchu\"",
+        "-DLOG_TAG=\"android.hardware.audio.service.ranchu\"",
+    ],
+    // android.hardware.audio.service.ranchu loads android.hardware.audio@6.0-impl
+    // which loads audio.r_submix.default which provides the r_submix device,
+    // see b/161485545. Should be retired once a better r_submix is available.
+    required: [
+        "android.hardware.audio@6.0-impl",
+        "audio.r_submix.default",
     ],
 }
diff --git a/audio/android.hardware.audio.service.ranchu.rc b/audio/android.hardware.audio.service.ranchu.rc
new file mode 100644
index 0000000..777c229
--- /dev/null
+++ b/audio/android.hardware.audio.service.ranchu.rc
@@ -0,0 +1,9 @@
+service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service.ranchu
+    class hal
+    user audioserver
+    # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
+    capabilities BLOCK_SUSPEND
+    ioprio rt 4
+    task_profiles ProcessCapacityHigh HighPerformance
+    onrestart restart audioserver
diff --git a/audio/debug.h b/audio/debug.h
new file mode 100644
index 0000000..60d884a
--- /dev/null
+++ b/audio/debug.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if 1
+
+#include <log/log.h>
+
+#define FAILURE(x) \
+    (ALOGE("%s:%s:%d failure: %s", __FILE__, __func__, __LINE__, #x), x)
+
+#else
+
+#define FAILURE(x) x
+
+#endif
diff --git a/audio/device_factory.cpp b/audio/device_factory.cpp
index e0bbf1f..32a9a04 100644
--- a/audio/device_factory.cpp
+++ b/audio/device_factory.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#include "device_factory.h"
-#include "primary_device.h"
 #include <system/audio.h>
 #include <log/log.h>
+#include "device_factory.h"
+#include "primary_device.h"
+#include "debug.h"
 
 namespace android {
 namespace hardware {
@@ -27,23 +28,34 @@
 
 using ::android::hardware::Void;
 
+#ifdef __LP64__
+#define LIB_PATH_PREFIX "vendor/lib64/hw/"
+#else
+#define LIB_PATH_PREFIX "vendor/lib/hw/"
+#endif
+
+DevicesFactory::DevicesFactory() {
+    mLegacyLib.reset(dlopen(
+        LIB_PATH_PREFIX "android.hardware.audio@6.0-impl.so", RTLD_NOW));
+    LOG_ALWAYS_FATAL_IF(!mLegacyLib);
+
+    typedef IDevicesFactory *(*Func)(const char *);
+    const auto func = reinterpret_cast<Func>(
+        dlsym(mLegacyLib.get(), "HIDL_FETCH_IDevicesFactory"));
+    LOG_ALWAYS_FATAL_IF(!func);
+
+    mLegacyFactory.reset((*func)("default"));
+    LOG_ALWAYS_FATAL_IF(!mLegacyFactory);
+}
+
 Return<void> DevicesFactory::openDevice(const hidl_string& device,
                                         openDevice_cb _hidl_cb) {
-    Result result = Result::OK;
-    std::unique_ptr<IDevice> dev;
-
-    if (device == AUDIO_HARDWARE_MODULE_ID_PRIMARY) {
-        dev = std::make_unique<PrimaryDevice>();
-    } else {
-        result = Result::INVALID_ARGUMENTS;
+    if (device == AUDIO_HARDWARE_MODULE_ID_PRIMARY)
+        _hidl_cb(Result::OK, new PrimaryDevice);
+    else {
+        mLegacyFactory->openDevice(device, _hidl_cb);
     }
 
-    if (!dev) {
-        ALOGE("DevicesFactory::%s:%d: failed, device='%s' result='%s'",
-              __func__, __LINE__, device.c_str(), toString(result).c_str());
-    }
-
-    _hidl_cb(result, dev.release());
     return Void();
 }
 
diff --git a/audio/device_factory.h b/audio/device_factory.h
index ac653d0..cc33be5 100644
--- a/audio/device_factory.h
+++ b/audio/device_factory.h
@@ -15,7 +15,9 @@
  */
 
 #pragma once
+#include <memory>
 #include <android/hardware/audio/6.0/IDevicesFactory.h>
+#include <dlfcn.h>
 
 namespace android {
 namespace hardware {
@@ -29,8 +31,20 @@
 using namespace ::android::hardware::audio::V6_0;
 
 struct DevicesFactory : public IDevicesFactory {
+    DevicesFactory();
+
     Return<void> openDevice(const hidl_string& device, openDevice_cb _hidl_cb) override;
     Return<void> openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) override;
+
+private:
+    struct DLDeleter {
+        void operator()(void* dl) const {
+            ::dlclose(dl);
+        }
+    };
+
+    std::unique_ptr<void, DLDeleter> mLegacyLib;
+    std::unique_ptr<IDevicesFactory> mLegacyFactory;
 };
 
 }  // namespace implementation
diff --git a/audio/device_port_sink.cpp b/audio/device_port_sink.cpp
new file mode 100644
index 0000000..0a34eb2
--- /dev/null
+++ b/audio/device_port_sink.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+#include <utils/Timers.h>
+#include "device_port_sink.h"
+#include "talsa.h"
+#include "util.h"
+#include "debug.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V6_0 {
+namespace implementation {
+
+namespace {
+
+struct TinyalsaSink : public DevicePortSink {
+    TinyalsaSink(unsigned pcmCard, unsigned pcmDevice,
+                 const AudioConfig &cfg, uint64_t &frames)
+            : mFrames(frames)
+            , mPcm(talsa::pcmOpen(pcmCard, pcmDevice,
+                                  util::countChannels(cfg.channelMask),
+                                  cfg.sampleRateHz,
+                                  cfg.frameCount,
+                                  true /* isOut */)) {}
+
+    Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
+        frames = mFrames;
+        ts = util::nsecs2TimeSpec(systemTime(SYSTEM_TIME_MONOTONIC));
+        return Result::OK;
+    }
+
+    int write(const void *data, size_t nBytes) override {
+        const int res = ::pcm_write(mPcm.get(), data, nBytes);
+        if (res < 0) {
+            return FAILURE(res);
+        } else if (res == 0) {
+            mFrames += ::pcm_bytes_to_frames(mPcm.get(), nBytes);
+            return nBytes;
+        } else {
+            mFrames += ::pcm_bytes_to_frames(mPcm.get(), res);
+            return res;
+        }
+    }
+
+    static std::unique_ptr<TinyalsaSink> create(unsigned pcmCard,
+                                                unsigned pcmDevice,
+                                                const AudioConfig &cfg,
+                                                uint64_t &frames) {
+        auto src = std::make_unique<TinyalsaSink>(pcmCard, pcmDevice, cfg, frames);
+        if (src->mPcm) {
+            return src;
+        } else {
+            return FAILURE(nullptr);
+        }
+    }
+
+private:
+    uint64_t &mFrames;
+    talsa::PcmPtr mPcm;
+};
+
+struct NullSink : public DevicePortSink {
+    NullSink(const AudioConfig &cfg, uint64_t &frames)
+            : mFrames(frames)
+            , mSampleRateHz(cfg.sampleRateHz)
+            , mNChannels(util::countChannels(cfg.channelMask))
+            , mTimestamp(systemTime(SYSTEM_TIME_MONOTONIC)) {}
+
+    Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
+        simulatePresentationPosition();
+        frames = mFrames;
+        ts = util::nsecs2TimeSpec(mTimestamp);
+        return Result::OK;
+    }
+
+    int write(const void *, size_t nBytes) override {
+        simulatePresentationPosition();
+        mAvailableFrames += nBytes / mNChannels / sizeof(int16_t);
+        return nBytes;
+    }
+
+    void simulatePresentationPosition() {
+        const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+        const nsecs_t deltaNs = nowNs - mTimestamp;
+        const uint64_t deltaFrames = uint64_t(mSampleRateHz) * ns2ms(deltaNs) / 1000;
+        const uint64_t f = std::min(deltaFrames, mAvailableFrames);
+
+        mFrames += f;
+        mAvailableFrames -= f;
+        if (mAvailableFrames) {
+            mTimestamp += us2ns(f * 1000000 / mSampleRateHz);
+        } else {
+            mTimestamp = nowNs;
+        }
+    }
+
+    static std::unique_ptr<NullSink> create(const AudioConfig &cfg,
+                                            uint64_t &frames) {
+        return std::make_unique<NullSink>(cfg, frames);
+    }
+
+private:
+    uint64_t &mFrames;
+    const unsigned mSampleRateHz;
+    const unsigned mNChannels;
+    uint64_t mAvailableFrames = 0;
+    nsecs_t mTimestamp;
+};
+
+}  // namespace
+
+std::unique_ptr<DevicePortSink>
+DevicePortSink::create(const DeviceAddress &address,
+                       const AudioConfig &cfg,
+                       const hidl_bitfield<AudioOutputFlag> &flags,
+                       uint64_t &frames) {
+    (void)flags;
+
+    if (cfg.format != AudioFormat::PCM_16_BIT) {
+        ALOGE("%s:%d Only PCM_16_BIT is supported", __func__, __LINE__);
+        return FAILURE(nullptr);
+    }
+
+    switch (address.device) {
+    case AudioDevice::OUT_SPEAKER:
+        return TinyalsaSink::create(talsa::kPcmCard, talsa::kPcmDevice,
+                                    cfg, frames);
+
+    case AudioDevice::OUT_TELEPHONY_TX:
+        return NullSink::create(cfg, frames);
+
+    default:
+        ALOGE("%s:%d unsupported device: %x", __func__, __LINE__, address.device);
+        return FAILURE(nullptr);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V6_0
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/device_port_sink.h b/audio/device_port_sink.h
new file mode 100644
index 0000000..5714cd0
--- /dev/null
+++ b/audio/device_port_sink.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <memory>
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/audio/6.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V6_0 {
+namespace implementation {
+
+using namespace ::android::hardware::audio::common::V6_0;
+using namespace ::android::hardware::audio::V6_0;
+
+struct DevicePortSink {
+    virtual ~DevicePortSink() {}
+    virtual Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) = 0;
+    virtual int write(const void *data, size_t nBytes) = 0;
+
+    static std::unique_ptr<DevicePortSink> create(const DeviceAddress &,
+                                                  const AudioConfig &,
+                                                  const hidl_bitfield<AudioOutputFlag> &,
+                                                  uint64_t &frames);
+};
+
+}  // namespace implementation
+}  // namespace V6_0
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/device_port_source.cpp b/audio/device_port_source.cpp
new file mode 100644
index 0000000..a82d281
--- /dev/null
+++ b/audio/device_port_source.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cmath>
+#include <chrono>
+#include <thread>
+#include <audio_utils/channels.h>
+#include <audio_utils/format.h>
+#include <log/log.h>
+#include <utils/Timers.h>
+#include "device_port_source.h"
+#include "talsa.h"
+#include "util.h"
+#include "debug.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V6_0 {
+namespace implementation {
+
+namespace {
+
+struct TinyalsaSource : public DevicePortSource {
+    TinyalsaSource(unsigned pcmCard, unsigned pcmDevice,
+                   const AudioConfig &cfg, uint64_t &frames)
+            : mFrames(frames)
+            , mPcm(talsa::pcmOpen(pcmCard, pcmDevice,
+                                  util::countChannels(cfg.channelMask),
+                                  cfg.sampleRateHz,
+                                  cfg.frameCount,
+                                  false /* isOut */)) {}
+
+    Result getCapturePosition(uint64_t &frames, uint64_t &time) override {
+        frames = mFrames;
+        time = systemTime(SYSTEM_TIME_MONOTONIC);
+        return Result::OK;
+    }
+
+    int read(void *data, size_t toReadBytes) override {
+        const int res = ::pcm_read(mPcm.get(), data, toReadBytes);
+        if (res < 0) {
+            return FAILURE(res);
+        } else if (res == 0) {
+            mFrames += ::pcm_bytes_to_frames(mPcm.get(), toReadBytes);
+            return toReadBytes;
+        } else {
+            mFrames += ::pcm_bytes_to_frames(mPcm.get(), res);
+            return res;
+        }
+    }
+
+    static std::unique_ptr<TinyalsaSource> create(unsigned pcmCard,
+                                                  unsigned pcmDevice,
+                                                  const AudioConfig &cfg,
+                                                  uint64_t &frames) {
+        auto src = std::make_unique<TinyalsaSource>(pcmCard, pcmDevice, cfg, frames);
+        if (src->mPcm) {
+            return src;
+        } else {
+            return FAILURE(nullptr);
+        }
+    }
+
+private:
+    uint64_t &mFrames;
+    talsa::PcmPtr mPcm;
+};
+
+template <class G> struct GeneratedSource : public DevicePortSource {
+    GeneratedSource(const AudioConfig &cfg, uint64_t &frames, G generator)
+            : mFrames(frames)
+            , mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
+            , mSampleRateHz(cfg.sampleRateHz)
+            , mNChannels(util::countChannels(cfg.channelMask))
+            , mGenerator(std::move(generator)) {}
+
+    Result getCapturePosition(uint64_t &frames, uint64_t &time) override {
+        const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+        const uint64_t nowFrames = getNowFrames(nowNs);
+        mFrames += (nowFrames - mPreviousFrames);
+        mPreviousFrames = nowFrames;
+        frames = mFrames;
+        time = nowNs;
+        return Result::OK;
+    }
+
+    uint64_t getNowFrames(const nsecs_t nowNs) const {
+        return uint64_t(mSampleRateHz) * ns2ms(nowNs - mStartNs) / 1000;
+    }
+
+    int read(void *data, size_t toReadBytes) override {
+        int16_t *samples = static_cast<int16_t *>(data);
+        const unsigned nChannels = mNChannels;
+        const unsigned requestedFrames = toReadBytes / nChannels / sizeof(*samples);
+
+        unsigned availableFrames;
+        while (true) {
+            const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+            availableFrames = getNowFrames(nowNs) - mSentFrames;
+            if (availableFrames < requestedFrames / 2) {
+                const unsigned neededMoreFrames = requestedFrames / 2 - availableFrames;
+
+                using namespace std::chrono_literals;
+                std::this_thread::sleep_for(1s * neededMoreFrames / mSampleRateHz);
+            } else {
+                break;
+            }
+        }
+
+        const unsigned nFrames = std::min(requestedFrames, availableFrames);
+        mGenerator(samples, nFrames);
+        const size_t sizeBytes = nFrames * nChannels * sizeof(*samples);
+        if (nChannels > 1) {
+            adjust_channels(samples, 1, samples, nChannels,
+                            sizeof(*samples), sizeBytes);
+        }
+
+        mSentFrames += nFrames;
+        return sizeBytes;
+    }
+
+private:
+    uint64_t &mFrames;
+    const nsecs_t mStartNs;
+    const unsigned mSampleRateHz;
+    const unsigned mNChannels;
+    uint64_t mPreviousFrames = 0;
+    uint64_t mSentFrames = 0;
+    G mGenerator;
+};
+
+std::vector<int16_t> convertFloatsToInt16(const std::vector<float> &pcmFloat) {
+    std::vector<int16_t> pcmI16(pcmFloat.size());
+
+    memcpy_by_audio_format(pcmI16.data(),   AUDIO_FORMAT_PCM_16_BIT,
+                           pcmFloat.data(), AUDIO_FORMAT_PCM_FLOAT,
+                           pcmFloat.size());
+
+    return pcmI16;
+}
+
+// https://en.wikipedia.org/wiki/Busy_signal
+struct BusySignalGenerator {
+    explicit BusySignalGenerator(const uint32_t sampleRateHz) : mSampleRateHz(sampleRateHz) {
+        // 24/480 = 31/620, mValues must contain 50ms of audio samples
+        const size_t sz = sampleRateHz / 20;
+        std::vector<float> pcm(sz);
+        for (unsigned i = 0; i < sz; ++i) {
+            const double a = double(i) * M_PI * 2 / sampleRateHz;
+            pcm[i] = .5 * (sin(480 * a) + sin(620 * a));
+        }
+        mValues = convertFloatsToInt16(pcm);
+    }
+
+    void operator()(int16_t* s, size_t n) {
+        const unsigned rate = mSampleRateHz;
+        const unsigned rateHalf = rate / 2;
+        const int16_t *const vals = mValues.data();
+        const size_t valsSz = mValues.size();
+        size_t i = mI;
+
+        while (n > 0) {
+            size_t len;
+            if (i < rateHalf) {
+                const size_t valsOff = i % valsSz;
+                len = std::min(n, std::min(rateHalf - i, valsSz - valsOff));
+                memcpy(s, vals + valsOff, len * sizeof(*s));
+            } else {
+                len = std::min(n, rate - i);
+                memset(s, 0, len * sizeof(*s));
+            }
+            s += len;
+            i = (i + len) % rate;
+            n -= len;
+        }
+
+        mI = i;
+    }
+
+private:
+    const unsigned mSampleRateHz;
+    std::vector<int16_t> mValues;
+    size_t mI = 0;
+};
+
+struct RepeatGenerator {
+    explicit RepeatGenerator(const std::vector<float> &pcm)
+            : mValues(convertFloatsToInt16(pcm)) {}
+
+    void operator()(int16_t* s, size_t n) {
+        const int16_t *const vals = mValues.data();
+        const size_t valsSz = mValues.size();
+        size_t i = mI;
+
+        while (n > 0) {
+            const size_t len = std::min(n, valsSz - i);
+            memcpy(s, vals + i, len * sizeof(*s));
+            s += len;
+            i = (i + len) % valsSz;
+            n -= len;
+        }
+
+        mI = i;
+    }
+
+private:
+    const std::vector<int16_t> mValues;
+    size_t mI = 0;
+};
+
+std::vector<float> generateSinePattern(uint32_t sampleRateHz,
+                                       double freq,
+                                       double amp) {
+    std::vector<float> result(3 * sampleRateHz / freq + .5);
+
+    for (size_t i = 0; i < result.size(); ++i) {
+        const double a = double(i) * M_PI * 2 / sampleRateHz;
+        result[i] = amp * sin(a * freq);
+    }
+
+    return result;
+}
+
+template <class G> std::unique_ptr<GeneratedSource<G>>
+createGeneratedSource(const AudioConfig &cfg, uint64_t &frames, G generator) {
+    return std::make_unique<GeneratedSource<G>>(cfg, frames, std::move(generator));
+}
+
+}  // namespace
+
+std::unique_ptr<DevicePortSource>
+DevicePortSource::create(const DeviceAddress &address,
+                         const AudioConfig &cfg,
+                         const hidl_bitfield<AudioOutputFlag> &flags,
+                         uint64_t &frames) {
+    (void)flags;
+
+    if (cfg.format != AudioFormat::PCM_16_BIT) {
+        ALOGE("%s:%d Only PCM_16_BIT is supported", __func__, __LINE__);
+        return FAILURE(nullptr);
+    }
+
+    switch (address.device) {
+    case AudioDevice::IN_BUILTIN_MIC:
+        return TinyalsaSource::create(talsa::kPcmCard, talsa::kPcmDevice,
+                                      cfg, frames);
+
+    case AudioDevice::IN_TELEPHONY_RX:
+        return createGeneratedSource(cfg, frames,
+                                     BusySignalGenerator(cfg.sampleRateHz));
+
+    case AudioDevice::IN_FM_TUNER:
+        return createGeneratedSource(
+            cfg, frames,
+            RepeatGenerator(generateSinePattern(cfg.sampleRateHz, 440.0, 1.0)));
+
+    default:
+        ALOGE("%s:%d unsupported device: %x", __func__, __LINE__, address.device);
+        return FAILURE(nullptr);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V6_0
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/device_port_source.h b/audio/device_port_source.h
new file mode 100644
index 0000000..3cc39ff
--- /dev/null
+++ b/audio/device_port_source.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <memory>
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/audio/6.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V6_0 {
+namespace implementation {
+
+using namespace ::android::hardware::audio::common::V6_0;
+using namespace ::android::hardware::audio::V6_0;
+
+struct DevicePortSource {
+    virtual ~DevicePortSource() {}
+    virtual Result getCapturePosition(uint64_t &frames, uint64_t &time) = 0;
+    virtual int read(void *data, size_t nBytes) = 0;
+
+    static std::unique_ptr<DevicePortSource> create(const DeviceAddress &,
+                                                    const AudioConfig &,
+                                                    const hidl_bitfield<AudioOutputFlag> &,
+                                                    uint64_t &frames);
+};
+
+}  // namespace implementation
+}  // namespace V6_0
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/entry.cpp b/audio/entry.cpp
index 1d48f43..7cbeb6d 100644
--- a/audio/entry.cpp
+++ b/audio/entry.cpp
@@ -14,12 +14,37 @@
  * limitations under the License.
  */
 
+#include <binder/ProcessState.h>
+#include <hwbinder/ProcessState.h>
+#include <hidl/LegacySupport.h>
 #include "device_factory.h"
 
-using android::hardware::audio::V6_0::IDevicesFactory;
-using android::hardware::audio::V6_0::implementation::DevicesFactory;
+int main(int, char**) {
+    using ::android::sp;
+    using ::android::OK;
+    using ::android::hardware::audio::V6_0::IDevicesFactory;
+    using ::android::hardware::audio::V6_0::implementation::DevicesFactory;
+    using ::android::hardware::registerPassthroughServiceImplementation;
 
-extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name) {
-    (void)name;
-    return new DevicesFactory();
+    ::android::ProcessState::initWithDriver("/dev/vndbinder");
+    ::android::ProcessState::self()->startThreadPool();
+    ::android::hardware::configureRpcThreadpool(16, true /* callerWillJoin */);
+
+    sp<IDevicesFactory> factory(new DevicesFactory());
+    if (factory->registerAsService() != ::android::NO_ERROR) {
+        return -EINVAL;
+    }
+
+    if (registerPassthroughServiceImplementation(
+        "android.hardware.audio.effect@6.0::IEffectsFactory") != OK) {
+        return -EINVAL;
+    }
+
+    if (registerPassthroughServiceImplementation(
+        "android.hardware.soundtrigger@2.2::ISoundTriggerHw") != OK) {
+        return -EINVAL;
+    }
+
+    ::android::hardware::joinRpcThreadpool();
+    return 0;
 }
diff --git a/audio/io_thread.cpp b/audio/io_thread.cpp
index 81982b3..b87c5e4 100644
--- a/audio/io_thread.cpp
+++ b/audio/io_thread.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "io_thread.h"
+#include "debug.h"
 
 namespace android {
 namespace hardware {
@@ -24,7 +25,15 @@
 
 bool IOThread::notify(const uint32_t mask) {
     EventFlag *evf = getEventFlag();
-    return evf ? (NO_ERROR == evf->wake(mask)) : false;
+    if (evf) {
+        if (NO_ERROR == evf->wake(mask)) {
+            return true;
+        } else {
+            return FAILURE(false);
+        }
+    } else {
+        return FAILURE(false);
+    }
 }
 
 bool IOThread::standby() {
diff --git a/audio/policy/audio_policy_configuration.xml b/audio/policy/audio_policy_configuration.xml
index f631bb0..34e8aff 100644
--- a/audio/policy/audio_policy_configuration.xml
+++ b/audio/policy/audio_policy_configuration.xml
@@ -24,6 +24,9 @@
         <!-- Primary Audio HAL -->
         <xi:include href="primary_audio_policy_configuration.xml"/>
 
+        <!-- Remote Submix Audio HAL -->
+        <xi:include href="r_submix_audio_policy_configuration.xml"/>
+
     </modules>
     <!-- End of Modules section -->
 
diff --git a/audio/policy/primary_audio_policy_configuration.xml b/audio/policy/primary_audio_policy_configuration.xml
index f9ac2c3..33a47d7 100644
--- a/audio/policy/primary_audio_policy_configuration.xml
+++ b/audio/policy/primary_audio_policy_configuration.xml
@@ -4,6 +4,9 @@
     <attachedDevices>
         <item>Speaker</item>
         <item>Built-In Mic</item>
+        <item>Telephony Tx</item>
+        <item>Telephony Rx</item>
+        <item>FM Tuner</item>
     </attachedDevices>
     <defaultOutputDevice>Speaker</defaultOutputDevice>
     <mixPorts>
@@ -15,18 +18,47 @@
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                      samplingRates="44100" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
         </mixPort>
+
+        <mixPort name="telephony_tx" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
+        </mixPort>
+        <mixPort name="telephony_rx" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+        </mixPort>
+
+        <mixPort name="fm_tuner" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+        </mixPort>
    </mixPorts>
    <devicePorts>
         <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
         </devicePort>
+        <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
+        </devicePort>
 
         <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
         </devicePort>
+        <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source">
+        </devicePort>
+
+        <devicePort tagName="FM Tuner" type="AUDIO_DEVICE_IN_FM_TUNER" role="source">
+        </devicePort>
     </devicePorts>
     <routes>
         <route type="mix" sink="Speaker"
                sources="primary output"/>
         <route type="mix" sink="primary input"
                sources="Built-In Mic"/>
+
+        <route type="mix" sink="telephony_rx"
+               sources="Telephony Rx"/>
+        <route type="mix" sink="Telephony Tx"
+               sources="telephony_tx"/>
+
+        <route type="mix" sink="fm_tuner"
+               sources="FM Tuner"/>
     </routes>
 </module>
diff --git a/audio/primary_device.cpp b/audio/primary_device.cpp
index 838a155..9f39d08 100644
--- a/audio/primary_device.cpp
+++ b/audio/primary_device.cpp
@@ -20,6 +20,7 @@
 #include "stream_in.h"
 #include "stream_out.h"
 #include "util.h"
+#include "debug.h"
 
 namespace android {
 namespace hardware {
@@ -28,7 +29,7 @@
 namespace implementation {
 
 constexpr size_t kInBufferDurationMs = 15;
-constexpr size_t kOutBufferDurationMs = 15;
+constexpr size_t kOutBufferDurationMs = 22;
 
 using ::android::hardware::Void;
 
@@ -48,28 +49,28 @@
 }
 
 Return<Result> PrimaryDevice::initCheck() {
-    return mMixer ? Result::OK : Result::NOT_INITIALIZED;
+    return mMixer ? Result::OK : FAILURE(Result::NOT_INITIALIZED);
 }
 
 Return<Result> PrimaryDevice::setMasterVolume(float volume) {
-    if (volume < 0 || volume > 1.0) {
-        return Result::INVALID_ARGUMENTS;
+    if (isnan(volume) || volume < 0 || volume > 1.0) {
+        return FAILURE(Result::INVALID_ARGUMENTS);
     }
 
     if (!mMixerMasterVolumeCtl) {
-        return Result::INVALID_STATE;
+        return FAILURE(Result::INVALID_STATE);
     }
 
     talsa::mixerSetPercentAll(mMixerMasterVolumeCtl, int(100 * volume));
+    mMasterVolume = volume;
     return Result::OK;
 }
 
 Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) {
     if (mMixerMasterVolumeCtl) {
-        _hidl_cb(Result::OK,
-                 mixer_ctl_get_percent(mMixerMasterVolumeCtl, 0) / 100.0);
+        _hidl_cb(Result::OK, mMasterVolume);
     } else {
-        _hidl_cb(Result::INVALID_STATE, 0);
+        _hidl_cb(FAILURE(Result::INVALID_STATE), 0);
     }
 
     return Void();
@@ -80,7 +81,7 @@
         talsa::mixerSetValueAll(mMixerCaptureSwitchCtl, mute ? 0 : 1);
         return Result::OK;
     } else {
-        return Result::INVALID_STATE;
+        return FAILURE(Result::INVALID_STATE);
     }
 }
 
@@ -89,7 +90,7 @@
         const int value = mixer_ctl_get_value(mMixerCaptureSwitchCtl, 0);
         _hidl_cb(Result::OK, value == 0);
     } else {
-        _hidl_cb(Result::INVALID_STATE, 0);
+        _hidl_cb(FAILURE(Result::INVALID_STATE), 0);
     }
     return Void();
 }
@@ -99,7 +100,7 @@
         talsa::mixerSetValueAll(mMixerMasterPaybackSwitchCtl, mute ? 0 : 1);
         return Result::OK;
     } else {
-        return Result::INVALID_STATE;
+        return FAILURE(Result::INVALID_STATE);
     }
 }
 
@@ -108,7 +109,7 @@
         const int value = mixer_ctl_get_value(mMixerMasterPaybackSwitchCtl, 0);
         _hidl_cb(Result::OK, value == 0);
     } else {
-        _hidl_cb(Result::NOT_SUPPORTED, 0);
+        _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
     }
 
     return Void();
@@ -126,7 +127,7 @@
         _hidl_cb(Result::OK, sz);
     } else {
         ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__);
-        _hidl_cb(Result::INVALID_ARGUMENTS, 0);
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), 0);
     }
 
     return Void();
@@ -147,7 +148,7 @@
                  config);
     } else {
         ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__);
-        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, suggestedConfig);
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), nullptr, suggestedConfig);
     }
 
     return Void();
@@ -168,49 +169,76 @@
                  config);
     } else {
         ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__);
-        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, suggestedConfig);
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), nullptr, suggestedConfig);
     }
 
     return Void();
 }
 
 Return<bool> PrimaryDevice::supportsAudioPatches() {
-    return false;
+    return true;
 }
 
 Return<void> PrimaryDevice::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
                                              const hidl_vec<AudioPortConfig>& sinks,
                                              createAudioPatch_cb _hidl_cb) {
-    (void)sources;
-    (void)sinks;
-    _hidl_cb(Result::NOT_SUPPORTED, 0);
+    if (sources.size() == 1 && sinks.size() == 1) {
+        AudioPatch patch;
+        patch.source = sources[0];
+        patch.sink = sinks[0];
+
+        AudioPatchHandle handle;
+        while (true) {
+            handle = mNextAudioPatchHandle;
+            mNextAudioPatchHandle = std::max(handle + 1, 0);
+            if (mAudioPatches.insert({handle, patch}).second) {
+                break;
+            }
+        }
+
+        _hidl_cb(Result::OK, handle);
+    } else {
+        _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
+    }
+
     return Void();
 }
 
-Return<void> PrimaryDevice::updateAudioPatch(int32_t previousPatch,
+Return<void> PrimaryDevice::updateAudioPatch(AudioPatchHandle previousPatchHandle,
                                              const hidl_vec<AudioPortConfig>& sources,
                                              const hidl_vec<AudioPortConfig>& sinks,
                                              updateAudioPatch_cb _hidl_cb) {
-    (void)previousPatch;
-    (void)sources;
-    (void)sinks;
-    _hidl_cb(Result::NOT_SUPPORTED, 0);
+    const auto i = mAudioPatches.find(previousPatchHandle);
+    if (i == mAudioPatches.end()) {
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), previousPatchHandle);
+    } else {
+        if (sources.size() == 1 && sinks.size() == 1) {
+            AudioPatch patch;
+            patch.source = sources[0];
+            patch.sink = sinks[0];
+            i->second = patch;
+
+            _hidl_cb(Result::OK, previousPatchHandle);
+        } else {
+            _hidl_cb(Result::NOT_SUPPORTED, previousPatchHandle);
+        }
+    }
+
     return Void();
 }
 
-Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) {
-    (void)patch;
-    return Result::NOT_SUPPORTED;
+Return<Result> PrimaryDevice::releaseAudioPatch(AudioPatchHandle patchHandle) {
+    return (mAudioPatches.erase(patchHandle) == 1) ? Result::OK : FAILURE(Result::INVALID_ARGUMENTS);
 }
 
 Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, port);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), port);
     return Void();
 }
 
 Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) {
     (void)config;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> PrimaryDevice::setScreenState(bool turnedOn) {
@@ -219,7 +247,7 @@
 }
 
 Return<void> PrimaryDevice::getHwAvSync(getHwAvSync_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
@@ -230,7 +258,7 @@
     if (keys.size() == 0) {
         _hidl_cb(Result::OK, {});
     } else {
-        _hidl_cb(Result::NOT_SUPPORTED, {});
+        _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     }
     return Void();
 }
@@ -250,12 +278,12 @@
 Return<Result> PrimaryDevice::setConnectedState(const DeviceAddress& dev_addr, bool connected) {
     (void)dev_addr;
     (void)connected;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> PrimaryDevice::close() {
     if (mNStreams > 0) {
-        return Result::INVALID_STATE;
+        return FAILURE(Result::INVALID_STATE);
     } else if (mMixer) {
         mMixerMasterVolumeCtl = nullptr;
         mMixerCaptureVolumeCtl = nullptr;
@@ -264,24 +292,24 @@
         mMixer.reset();
         return Result::OK;
     } else {
-        return Result::INVALID_STATE;
+        return FAILURE(Result::INVALID_STATE);
     }
 }
 
 Return<Result> PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t effectId) {
     (void)device;
     (void)effectId;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
     (void)device;
     (void)effectId;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
-    return (volume >= 0 && volume <= 1.0) ? Result::OK : Result::INVALID_ARGUMENTS;
+    return (volume >= 0 && volume <= 1.0) ? Result::OK : FAILURE(Result::INVALID_ARGUMENTS);
 }
 
 Return<Result> PrimaryDevice::setMode(AudioMode mode) {
@@ -293,78 +321,78 @@
         return Result::OK;
 
     default:
-        return Result::INVALID_ARGUMENTS;
+        return FAILURE(Result::INVALID_ARGUMENTS);
     }
 }
 
 Return<Result> PrimaryDevice::setBtScoHeadsetDebugName(const hidl_string& name) {
     (void)name;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, false);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false);
     return Void();
 }
 
 Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) {
     (void)enabled;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, false);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false);
     return Void();
 }
 
 Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) {
     (void)enabled;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, TtyMode::OFF);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), TtyMode::OFF);
     return Void();
 }
 
 Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
     (void)mode;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, false);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false);
     return Void();
 }
 
 Return<Result> PrimaryDevice::setHacEnabled(bool enabled) {
     (void)enabled;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> PrimaryDevice::getBtHfpEnabled(getBtHfpEnabled_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, false);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false);
     return Void();
 }
 
 Return<Result> PrimaryDevice::setBtHfpEnabled(bool enabled) {
     (void)enabled;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> PrimaryDevice::setBtHfpSampleRate(uint32_t sampleRateHz) {
     (void)sampleRateHz;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> PrimaryDevice::setBtHfpVolume(float volume) {
     (void)volume;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> PrimaryDevice::updateRotation(IPrimaryDevice::Rotation rotation) {
     (void)rotation;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 void PrimaryDevice::unrefDevice(IDevice *dev) {
diff --git a/audio/primary_device.h b/audio/primary_device.h
index 72b5c75..05964f3 100644
--- a/audio/primary_device.h
+++ b/audio/primary_device.h
@@ -17,6 +17,7 @@
 #pragma once
 #include <android/hardware/audio/6.0/IPrimaryDevice.h>
 #include <atomic>
+#include <unordered_map>
 #include "talsa.h"
 
 namespace android {
@@ -62,11 +63,11 @@
     Return<void> createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
                                   const hidl_vec<AudioPortConfig>& sinks,
                                   createAudioPatch_cb _hidl_cb) override;
-    Return<void> updateAudioPatch(int32_t previousPatch,
+    Return<void> updateAudioPatch(AudioPatchHandle previousPatch,
                                   const hidl_vec<AudioPortConfig>& sources,
                                   const hidl_vec<AudioPortConfig>& sinks,
                                   updateAudioPatch_cb _hidl_cb) override;
-    Return<Result> releaseAudioPatch(int32_t patch) override;
+    Return<Result> releaseAudioPatch(AudioPatchHandle patch) override;
     Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override;
     Return<Result> setAudioPortConfig(const AudioPortConfig& config) override;
     Return<Result> setScreenState(bool turnedOn) override;
@@ -107,7 +108,16 @@
     talsa::mixer_ctl_t  *mMixerCaptureVolumeCtl = nullptr;
     talsa::mixer_ctl_t  *mMixerMasterPaybackSwitchCtl = nullptr;
     talsa::mixer_ctl_t  *mMixerCaptureSwitchCtl = nullptr;
+    float               mMasterVolume = 1.0f;
     std::atomic<int>    mNStreams = 0;
+
+    struct AudioPatch {
+        AudioPortConfig source;
+        AudioPortConfig sink;
+    };
+
+    AudioPatchHandle    mNextAudioPatchHandle = 0;
+    std::unordered_map<AudioPatchHandle, AudioPatch> mAudioPatches;
 };
 
 }  // namespace implementation
diff --git a/audio/stream_common.cpp b/audio/stream_common.cpp
index 3ac4da8..6235f9a 100644
--- a/audio/stream_common.cpp
+++ b/audio/stream_common.cpp
@@ -17,6 +17,7 @@
 #include <log/log.h>
 #include "stream_common.h"
 #include "util.h"
+#include "debug.h"
 
 namespace android {
 namespace hardware {
@@ -64,7 +65,7 @@
 
 Result StreamCommon::setSampleRate(uint32_t sampleRateHz) const {
     (void)sampleRateHz;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 hidl_bitfield<AudioChannelMask> StreamCommon::getChannelMask() const {
@@ -82,7 +83,7 @@
 
 Result StreamCommon::setChannelMask(hidl_bitfield<AudioChannelMask> mask) const {
     (void)mask;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 AudioFormat StreamCommon::getFormat() const {
@@ -95,7 +96,7 @@
 
 Result StreamCommon::setFormat(AudioFormat format) const {
     (void)format;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 void StreamCommon::getAudioProperties(IStream::getAudioProperties_cb _hidl_cb) const {
@@ -108,7 +109,7 @@
 
 Result StreamCommon::setDevices(const hidl_vec<DeviceAddress>& devices) const {
     (void)devices;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 }  // namespace implementation
diff --git a/audio/stream_in.cpp b/audio/stream_in.cpp
index 89ca7e6..c3ef62f 100644
--- a/audio/stream_in.cpp
+++ b/audio/stream_in.cpp
@@ -20,9 +20,10 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include "stream_in.h"
+#include "device_port_source.h"
 #include "deleters.h"
-#include "talsa.h"
 #include "util.h"
+#include "debug.h"
 #include <sys/resource.h>
 #include <pthread.h>
 #include <cutils/sched_policy.h>
@@ -45,15 +46,8 @@
     typedef MessageQueue<IStreamIn::ReadStatus, kSynchronizedReadWrite> StatusMQ;
     typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
 
-    ReadThread(StreamIn *stream,
-               const unsigned nChannels,
-               const size_t sampleRateHz,
-               const size_t frameCount,
-               const size_t bufferSize)
+    ReadThread(StreamIn *stream, const size_t bufferSize)
             : mStream(stream)
-            , mNChannels(nChannels)
-            , mSampleRateHz(sampleRateHz)
-            , mFrameCount(frameCount)
             , mCommandMQ(1)
             , mStatusMQ(1)
             , mDataMQ(bufferSize, true /* EventFlag */) {
@@ -117,22 +111,20 @@
             }
 
             if (efState & STAND_BY_REQUEST) {
-                mPcm.reset();
+                mSource.reset();
                 mBuffer.reset();
             }
 
             if (efState & (MessageQueueFlagBits::NOT_FULL | 0)) {
-                if (!mPcm) {
+                if (!mSource) {
                     mBuffer.reset(new uint8_t[mDataMQ.getQuantumCount()]);
                     LOG_ALWAYS_FATAL_IF(!mBuffer);
 
-                    mPcm = talsa::pcmOpen(
-                        talsa::kPcmCard, talsa::kPcmDevice,
-                        mNChannels, mSampleRateHz, mFrameCount,
-                        false /* isOut */);
-                    LOG_ALWAYS_FATAL_IF(!mPcm);
-
-                    mPos.reset();
+                    mSource = DevicePortSource::create(mStream->getDeviceAddress(),
+                                                       mStream->getAudioConfig(),
+                                                       mStream->getAudioOutputFlags(),
+                                                       mStream->getFrameCounter());
+                    LOG_ALWAYS_FATAL_IF(!mSource);
                 }
 
                 processCommand();
@@ -160,7 +152,7 @@
             default:
                 ALOGE("ReadThread::%s:%d: Unknown read thread command code %d",
                       __func__, __LINE__, rParameters.command);
-                rStatus.retval = Result::NOT_SUPPORTED;
+                rStatus.retval = FAILURE(Result::NOT_SUPPORTED);
                 break;
         }
 
@@ -184,8 +176,6 @@
             if (!mDataMQ.write(&mBuffer[0], read)) {
                 ALOGE("ReadThread::%s:%d: mDataMQ.write failed", __func__, __LINE__);
             }
-
-            mPos.addFrames(pcm_bytes_to_frames(mPcm.get(), read));
             status.reply.read = read;
         }
 
@@ -193,15 +183,12 @@
     }
 
     Result doReadImpl(uint8_t *const data, const size_t toRead, size_t &read) {
-        const int res = pcm_read(mPcm.get(), data, toRead);
+        const int res = mSource->read(data, toRead);
         if (res < 0) {
             memset(data, 0, toRead);
             read = toRead;
-
-            ALOGE("ReadThread::%s:%d pcm_read failed with %s",
+            ALOGE("StreamInReadThread::%s:%d pcm_read failed with %s",
                   __func__, __LINE__, strerror(-res));
-        } else if (res == 0) {
-            read = toRead;
         } else {
             read = res;
         }
@@ -212,25 +199,20 @@
     IStreamIn::ReadStatus doGetCapturePosition() {
         IStreamIn::ReadStatus status;
 
-        status.retval = Result::OK;
-        nsecs_t t = 0;
-        mPos.now(mSampleRateHz, status.reply.capturePosition.frames, t);
-        status.reply.capturePosition.time = t;
+        status.retval = mSource->getCapturePosition(
+            status.reply.capturePosition.frames,
+            status.reply.capturePosition.time);
 
         return status;
     }
 
     StreamIn *const mStream;
-    const unsigned mNChannels;
-    const size_t mSampleRateHz;
-    const size_t mFrameCount;
     CommandMQ mCommandMQ;
     StatusMQ mStatusMQ;
     DataMQ mDataMQ;
     std::unique_ptr<EventFlag, deleters::forEventFlag> mEfGroup;
     std::unique_ptr<uint8_t[]> mBuffer;
-    talsa::PcmPtr mPcm;
-    util::StreamPosition mPos;
+    std::unique_ptr<DevicePortSource> mSource;
     std::thread mThread;
     std::promise<pthread_t> mTid;
 };
@@ -251,7 +233,7 @@
 }
 
 StreamIn::~StreamIn() {
-    close();
+    closeImpl(true);
 }
 
 Return<uint64_t> StreamIn::getFrameSize() {
@@ -314,12 +296,12 @@
 
 Return<Result> StreamIn::addEffect(uint64_t effectId) {
     (void)effectId;
-    return Result::INVALID_ARGUMENTS;
+    return FAILURE(Result::INVALID_ARGUMENTS);
 }
 
 Return<Result> StreamIn::removeEffect(uint64_t effectId) {
     (void)effectId;
-    return Result::INVALID_ARGUMENTS;
+    return FAILURE(Result::INVALID_ARGUMENTS);
 }
 
 Return<Result> StreamIn::standby() {
@@ -343,7 +325,7 @@
                                      const hidl_vec<hidl_string>& keys,
                                      getParameters_cb _hidl_cb) {
     (void)context;
-    _hidl_cb((keys.size() > 0) ? Result::NOT_SUPPORTED : Result::OK, {});
+    _hidl_cb((keys.size() > 0) ? FAILURE(Result::NOT_SUPPORTED) : Result::OK, {});
     return Void();
 }
 
@@ -356,48 +338,56 @@
 
 Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
     (void)hwAvSync;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamIn::start() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamIn::stop() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames,
                                         createMmapBuffer_cb _hidl_cb) {
     (void)minSizeFrames;
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
 Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
-Return<Result> StreamIn::close() {
+Result StreamIn::closeImpl(const bool fromDctor) {
     if (mDev) {
         mReadThread.reset();
         mUnrefDevice(mDev.get());
         mDev = nullptr;
         return Result::OK;
+    } else if (fromDctor) {
+        // closeImpl is always called from the dctor, it is ok if mDev is null,
+        // we don't want to log the error in this case.
+        return Result::OK;
     } else {
-        return Result::INVALID_STATE;
+        return FAILURE(Result::INVALID_STATE);
     }
 }
 
+Return<Result> StreamIn::close() {
+    return closeImpl(false);
+}
+
 Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
 Return<Result> StreamIn::setGain(float gain) {
     (void)gain;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
@@ -409,20 +399,16 @@
                                          uint32_t framesCount,
                                          prepareForReading_cb _hidl_cb) {
     if (!frameSize || !framesCount || frameSize > 256 || framesCount > (1u << 20)) {
-        _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {});
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {});
         return Void();
     }
 
     if (mReadThread) {  // INVALID_STATE if the method was already called.
-        _hidl_cb(Result::INVALID_STATE, {}, {}, {}, {});
+        _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {}, {}, {});
         return Void();
     }
 
-    auto t = std::make_unique<ReadThread>(this,
-                                          util::countChannels(mCommon.getChannelMask()),
-                                          mCommon.getSampleRate(),
-                                          mCommon.getFrameCount(),
-                                          frameSize * framesCount);
+    auto t = std::make_unique<ReadThread>(this, frameSize * framesCount);
 
     if (t->isRunning()) {
         _hidl_cb(Result::OK,
@@ -433,7 +419,7 @@
 
         mReadThread = std::move(t);
     } else {
-        _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {});
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {});
     }
 
     return Void();
@@ -444,7 +430,7 @@
 }
 
 Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, 0, 0);  // see ReadThread::doGetCapturePosition
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0, 0);  // see ReadThread::doGetCapturePosition
     return Void();
 }
 
@@ -455,12 +441,12 @@
 
 Return<Result> StreamIn::setMicrophoneDirection(MicrophoneDirection direction) {
     (void)direction;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamIn::setMicrophoneFieldDimension(float zoom) {
     (void)zoom;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 }  // namespace implementation
diff --git a/audio/stream_in.h b/audio/stream_in.h
index 13b28d8..2a76981 100644
--- a/audio/stream_in.h
+++ b/audio/stream_in.h
@@ -87,12 +87,23 @@
     Return<Result> setMicrophoneDirection(MicrophoneDirection direction) override;
     Return<Result> setMicrophoneFieldDimension(float zoom) override;
 
+    const DeviceAddress &getDeviceAddress() const { return mCommon.m_device; }
+    const AudioConfig &getAudioConfig() const { return mCommon.m_config; }
+    const hidl_bitfield<AudioOutputFlag> &getAudioOutputFlags() const { return mCommon.m_flags; }
+
+    uint64_t &getFrameCounter() { return mFrames; }
+
 private:
+    Result closeImpl(bool fromDctor);
+
     sp<IDevice> mDev;
     void (* const mUnrefDevice)(IDevice*);
     const StreamCommon mCommon;
     const SinkMetadata mSinkMetadata;
     std::unique_ptr<IOThread> mReadThread;
+
+    // The count is not reset to zero when output enters standby.
+    uint64_t mFrames = 0;
 };
 
 }  // namespace implementation
diff --git a/audio/stream_out.cpp b/audio/stream_out.cpp
index 8de1963..72b826f 100644
--- a/audio/stream_out.cpp
+++ b/audio/stream_out.cpp
@@ -21,9 +21,10 @@
 #include <hidl/Status.h>
 #include <math.h>
 #include "stream_out.h"
-#include "talsa.h"
+#include "device_port_sink.h"
 #include "deleters.h"
 #include "util.h"
+#include "debug.h"
 #include <sys/resource.h>
 #include <pthread.h>
 #include <cutils/sched_policy.h>
@@ -48,15 +49,8 @@
     typedef MessageQueue<IStreamOut::WriteStatus, kSynchronizedReadWrite> StatusMQ;
     typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
 
-    WriteThread(StreamOut *stream,
-                const unsigned nChannels,
-                const size_t sampleRateHz,
-                const size_t frameCount,
-                const size_t mqBufferSize)
+    WriteThread(StreamOut *stream, const size_t mqBufferSize)
             : mStream(stream)
-            , mNChannels(nChannels)
-            , mSampleRateHz(sampleRateHz)
-            , mFrameCount(frameCount)
             , mCommandMQ(1)
             , mStatusMQ(1)
             , mDataMQ(mqBufferSize, true /* EventFlag */) {
@@ -120,22 +114,19 @@
             }
 
             if (efState & STAND_BY_REQUEST) {
-                mPcm.reset();
-                mBuffer.reset();
+                mSink.reset();
             }
 
             if (efState & (MessageQueueFlagBits::NOT_EMPTY | 0)) {
-                if (!mPcm) {
+                if (!mSink) {
                     mBuffer.reset(new uint8_t[mDataMQ.getQuantumCount()]);
                     LOG_ALWAYS_FATAL_IF(!mBuffer);
 
-                    mPcm = talsa::pcmOpen(
-                        talsa::kPcmCard, talsa::kPcmDevice,
-                        mNChannels, mSampleRateHz, mFrameCount,
-                        true /* isOut */);
-                    LOG_ALWAYS_FATAL_IF(!mPcm);
-
-                    mPos.reset();
+                    mSink = DevicePortSink::create(mStream->getDeviceAddress(),
+                                                   mStream->getAudioConfig(),
+                                                   mStream->getAudioOutputFlags(),
+                                                   mStream->getFrameCounter());
+                    LOG_ALWAYS_FATAL_IF(!mSink);
                 }
 
                 processCommand();
@@ -167,7 +158,7 @@
             default:
                 ALOGE("WriteThread::%s:%d: Unknown write thread command code %d",
                       __func__, __LINE__, wCommand);
-                wStatus.retval = Result::NOT_SUPPORTED;
+                wStatus.retval = FAILURE(Result::NOT_SUPPORTED);
                 break;
         }
 
@@ -186,9 +177,8 @@
         const size_t availToRead = mDataMQ.availableToRead();
         size_t written = 0;
         if (mDataMQ.read(&mBuffer[0], availToRead)) {
+            applyVolume(&mBuffer[0], availToRead, mStream->getVolumeNumerator());
             status.retval = doWriteImpl(&mBuffer[0], availToRead, written);
-
-            mPos.addFrames(pcm_bytes_to_frames(mPcm.get(), written));
             status.reply.written = written;
         } else {
             ALOGE("WriteThread::%s:%d: mDataMQ.read failed", __func__, __LINE__);
@@ -198,10 +188,25 @@
         return status;
     }
 
+    static void applyVolume(void *buf, const size_t szBytes, const int32_t numerator) {
+        constexpr int32_t kDenominator = StreamOut::kVolumeDenominator;
+
+        if (numerator == kDenominator) {
+            return;
+        }
+
+        int16_t *samples = static_cast<int16_t *>(buf);
+        std::for_each(samples,
+                      samples + szBytes / sizeof(*samples),
+                      [numerator](int16_t &x) {
+                          x = (x * numerator + kDenominator / 2) / kDenominator;
+                      });
+    }
+
     IStreamOut::WriteStatus doGetPresentationPosition() {
         IStreamOut::WriteStatus status;
 
-        status.retval = doGetPresentationPositionImpl(
+        status.retval = mSink->getPresentationPosition(
             status.reply.presentationPosition.frames,
             status.reply.presentationPosition.timeStamp);
 
@@ -220,35 +225,25 @@
     Result doWriteImpl(const uint8_t *const data,
                        const size_t toWrite,
                        size_t &written) {
-        const int res = pcm_write(mPcm.get(), data, toWrite);
-        if (res) {
-            ALOGE("WriteThread::%s:%d: pcm_write failed with %s",
+        const int res = mSink->write(data, toWrite);
+        if (res < 0) {
+            ALOGE("WriteThread::%s:%d: DevicePortSink::write failed with %s",
                   __func__, __LINE__, strerror(-res));
+            written = toWrite;
+        } else {
+            written = res;
         }
 
-        written = toWrite;
-        return Result::OK;
-    }
-
-    Result doGetPresentationPositionImpl(uint64_t &frames, TimeSpec &ts) {
-        nsecs_t t = 0;
-        mPos.now(mSampleRateHz, frames, t);
-        ts.tvSec = ns2s(t);
-        ts.tvNSec = t - s2ns(ts.tvSec);
         return Result::OK;
     }
 
     StreamOut *const mStream;
-    const unsigned mNChannels;
-    const size_t mSampleRateHz;
-    const size_t mFrameCount;
     CommandMQ mCommandMQ;
     StatusMQ mStatusMQ;
     DataMQ mDataMQ;
     std::unique_ptr<EventFlag, deleters::forEventFlag> mEfGroup;
     std::unique_ptr<uint8_t[]> mBuffer;
-    talsa::PcmPtr mPcm;
-    util::StreamPosition mPos;
+    std::unique_ptr<DevicePortSink> mSink;
     std::thread mThread;
     std::promise<pthread_t> mTid;
 };
@@ -265,11 +260,10 @@
         : mDev(std::move(dev))
         , mUnrefDevice(unrefDevice)
         , mCommon(ioHandle, device, config, flags)
-        , mSourceMetadata(sourceMetadata) {
-}
+        , mSourceMetadata(sourceMetadata) {}
 
 StreamOut::~StreamOut() {
-    close();
+    closeImpl(true);
 }
 
 Return<uint64_t> StreamOut::getFrameSize() {
@@ -332,12 +326,12 @@
 
 Return<Result> StreamOut::addEffect(uint64_t effectId) {
     (void)effectId;
-    return Result::INVALID_ARGUMENTS;
+    return FAILURE(Result::INVALID_ARGUMENTS);
 }
 
 Return<Result> StreamOut::removeEffect(uint64_t effectId) {
     (void)effectId;
-    return Result::INVALID_ARGUMENTS;
+    return FAILURE(Result::INVALID_ARGUMENTS);
 }
 
 Return<Result> StreamOut::standby() {
@@ -361,7 +355,7 @@
                                       const hidl_vec<hidl_string>& keys,
                                       getParameters_cb _hidl_cb) {
     (void)context;
-    _hidl_cb((keys.size() > 0) ? Result::NOT_SUPPORTED : Result::OK, {});
+    _hidl_cb((keys.size() > 0) ? FAILURE(Result::NOT_SUPPORTED) : Result::OK, {});
     return Void();
 }
 
@@ -374,37 +368,45 @@
 
 Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
     (void)hwAvSync;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
-Return<Result> StreamOut::close() {
+Result StreamOut::closeImpl(const bool fromDctor) {
     if (mDev) {
         mWriteThread.reset();
         mUnrefDevice(mDev.get());
         mDev = nullptr;
         return Result::OK;
+    } else if (fromDctor) {
+        // closeImpl is always called from the dctor, it is ok if mDev is null,
+        // we don't want to log the error in this case.
+        return Result::OK;
     } else {
-        return Result::INVALID_STATE;
+        return FAILURE(Result::INVALID_STATE);
     }
 }
 
+Return<Result> StreamOut::close() {
+    return closeImpl(false);
+}
+
 Return<Result> StreamOut::start() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamOut::stop() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames,
                                          createMmapBuffer_cb _hidl_cb) {
     (void)minSizeFrames;
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
 Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
@@ -413,9 +415,13 @@
 }
 
 Return<Result> StreamOut::setVolume(float left, float right) {
-    (void)left;
-    (void)right;
-    return Result::NOT_SUPPORTED;
+    if (isnan(left) || left < 0.0f || left > 1.0f
+        || right < 0.0f || right > 1.0f || isnan(right)) {
+        return FAILURE(Result::INVALID_ARGUMENTS);
+    }
+
+    mVolumeNumerator = int16_t((left + right) * kVolumeDenominator / 2);
+    return Result::OK;
 }
 
 Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
@@ -427,20 +433,16 @@
                                           uint32_t framesCount,
                                           prepareForWriting_cb _hidl_cb) {
     if (!frameSize || !framesCount || frameSize > 256 || framesCount > (1u << 20)) {
-        _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {});
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {});
         return Void();
     }
 
     if (mWriteThread) {  // INVALID_STATE if the method was already called.
-        _hidl_cb(Result::INVALID_STATE, {}, {}, {}, {});
+        _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {}, {}, {});
         return Void();
     }
 
-    auto t = std::make_unique<WriteThread>(this,
-                                           util::countChannels(mCommon.getChannelMask()),
-                                           mCommon.getSampleRate(),
-                                           mCommon.getFrameCount(),
-                                           frameSize * framesCount);
+    auto t = std::make_unique<WriteThread>(this, frameSize * framesCount);
 
     if (t->isRunning()) {
         _hidl_cb(Result::OK,
@@ -451,34 +453,34 @@
 
         mWriteThread = std::move(t);
     } else {
-        _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {});
+        _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {});
     }
 
     return Void();
 }
 
 Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, 0);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
     return Void();
 }
 
 Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, 0);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
     return Void();
 }
 
 Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
     (void)callback;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamOut::clearCallback() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& callback) {
     (void)callback;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
@@ -487,11 +489,11 @@
 }
 
 Return<Result> StreamOut::pause() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamOut::resume() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<bool> StreamOut::supportsDrain() {
@@ -500,15 +502,15 @@
 
 Return<Result> StreamOut::drain(AudioDrain type) {
     (void)type;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamOut::flush() {
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {}, {});    // see WriteThread::doGetPresentationPosition
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}, {});    // see WriteThread::doGetPresentationPosition
     return Void();
 }
 
@@ -516,37 +518,37 @@
                                              int32_t programId) {
     (void)presentationId;
     (void)programId;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
 Return<Result> StreamOut::setDualMonoMode(DualMonoMode mode) {
     (void)mode;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, 0);
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
     return Void();
 }
 
 Return<Result> StreamOut::setAudioDescriptionMixLevel(float leveldB) {
     (void)leveldB;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
     return Void();
 }
 
 Return<Result> StreamOut::setPlaybackRateParameters(const PlaybackRate &playbackRate) {
     (void)playbackRate;
-    return Result::NOT_SUPPORTED;
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 }  // namespace implementation
diff --git a/audio/stream_out.h b/audio/stream_out.h
index c55ad8c..79adef3 100644
--- a/audio/stream_out.h
+++ b/audio/stream_out.h
@@ -15,6 +15,7 @@
  */
 
 #pragma once
+#include <atomic>
 #include <android/hardware/audio/6.0/IStreamOut.h>
 #include <android/hardware/audio/6.0/IDevice.h>
 #include "stream_common.h"
@@ -44,6 +45,8 @@
               const SourceMetadata& sourceMetadata);
     ~StreamOut();
 
+    static constexpr int16_t kVolumeDenominator = 1 << 14;
+
     // IStream
     Return<uint64_t> getFrameSize() override;
     Return<uint64_t> getFrameCount() override;
@@ -101,12 +104,25 @@
     Return<void> getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) override;
     Return<Result> setPlaybackRateParameters(const PlaybackRate &playbackRate) override;
 
+    int16_t getVolumeNumerator() const { return mVolumeNumerator; };
+    const DeviceAddress &getDeviceAddress() const { return mCommon.m_device; }
+    const AudioConfig &getAudioConfig() const { return mCommon.m_config; }
+    const hidl_bitfield<AudioOutputFlag> &getAudioOutputFlags() const { return mCommon.m_flags; }
+
+    uint64_t &getFrameCounter() { return mFrames; }
+
 private:
+    Result closeImpl(bool fromDctor);
+
     sp<IDevice> mDev;
     void (* const mUnrefDevice)(IDevice*);
     const StreamCommon mCommon;
     const SourceMetadata mSourceMetadata;
     std::unique_ptr<IOThread> mWriteThread;
+    std::atomic<int16_t> mVolumeNumerator = kVolumeDenominator;
+
+    // The count is not reset to zero when output enters standby.
+    uint64_t mFrames = 0;
 };
 
 }  // namespace implementation
diff --git a/audio/talsa.cpp b/audio/talsa.cpp
index 61ea140..12c22b0 100644
--- a/audio/talsa.cpp
+++ b/audio/talsa.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include "talsa.h"
 #include <log/log.h>
+#include "talsa.h"
+#include "debug.h"
 
 namespace android {
 namespace hardware {
@@ -60,7 +61,7 @@
               "frameCount=%zu isOut=%d with %s", __func__, __LINE__,
               nChannels, sampleRateHz, frameCount, isOut,
               pcm_get_error(pcm.get()));
-        return nullptr;
+        return FAILURE(nullptr);
     }
 }
 
diff --git a/audio/util.cpp b/audio/util.cpp
index 746e37d..dbe620b 100644
--- a/audio/util.cpp
+++ b/audio/util.cpp
@@ -18,6 +18,7 @@
 #include <cutils/bitops.h>
 #include <system/audio.h>
 #include "util.h"
+#include "debug.h"
 
 namespace android {
 namespace hardware {
@@ -59,11 +60,16 @@
     }
 
     suggest = kSupportedRatesHz.back();
-    return false;
+    return FAILURE(false);
+}
+
+size_t align(size_t v, size_t a) {
+    return (v + a - 1) / a * a;
 }
 
 size_t getBufferSizeFrames(size_t duration_ms, uint32_t sample_rate) {
-    return sample_rate * duration_ms / 1000;
+    // AudioFlinger requires the buffer to be aligned by 16 frames
+    return align(sample_rate * duration_ms / 1000, 16);
 }
 
 }  // namespace
@@ -107,7 +113,7 @@
                       kSupportedOutChannelMask.end(),
                       cfg.channelMask) == kSupportedOutChannelMask.end()) {
             suggested.channelMask = AudioChannelMask::OUT_STEREO | 0;
-            valid = false;
+            valid = FAILURE(false);
         } else {
             suggested.channelMask = cfg.channelMask;
         }
@@ -116,7 +122,7 @@
                       kSupportedInChannelMask.end(),
                       cfg.channelMask) == kSupportedInChannelMask.end()) {
             suggested.channelMask = AudioChannelMask::IN_STEREO | 0;
-            valid = false;
+            valid = FAILURE(false);
         } else {
             suggested.channelMask = cfg.channelMask;
         }
@@ -126,7 +132,7 @@
                   kSupportedAudioFormats.end(),
                   cfg.format) == kSupportedAudioFormats.end()) {
         suggested.format = AudioFormat::PCM_16_BIT;
-        valid = false;
+        valid = FAILURE(false);
     } else {
         suggested.format = cfg.format;
     }
@@ -140,25 +146,11 @@
     return valid;
 }
 
-StreamPosition::StreamPosition() : mTimestamp(systemTime(SYSTEM_TIME_MONOTONIC)) {}
-
-void StreamPosition::addFrames(uint64_t n) {
-    mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-    mFrames += n;
-}
-
-void StreamPosition::now(const size_t sampleRateHz,
-                         uint64_t &frames,
-                         nsecs_t &timestamp) const {
-    const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    const uint64_t deltaUs = ns2us(now - mTimestamp);
-
-    frames = mFrames + sampleRateHz * deltaUs / 1000000;
-    timestamp = now;
-}
-
-void StreamPosition::reset() {
-    *this = StreamPosition();
+TimeSpec nsecs2TimeSpec(nsecs_t ns) {
+    TimeSpec ts;
+    ts.tvSec = ns2s(ns);
+    ts.tvNSec = ns - s2ns(ts.tvSec);
+    return ts;
 }
 
 }  // namespace util
diff --git a/audio/util.h b/audio/util.h
index bfac69a..aae8f53 100644
--- a/audio/util.h
+++ b/audio/util.h
@@ -43,15 +43,7 @@
                       const AudioConfig &cfg,
                       AudioConfig &suggested);
 
-struct StreamPosition {
-    StreamPosition();
-    void addFrames(uint64_t n);
-    void now(size_t sampleRateHz, uint64_t &frames, nsecs_t &timestamp) const;
-    void reset();
-
-    uint64_t mFrames = 0;
-    nsecs_t mTimestamp;
-};
+TimeSpec nsecs2TimeSpec(nsecs_t);
 
 }  // namespace util
 }  // namespace implementation
diff --git a/camera/EmulatedFakeCamera3.cpp b/camera/EmulatedFakeCamera3.cpp
index 2009a33..2da2c4d 100644
--- a/camera/EmulatedFakeCamera3.cpp
+++ b/camera/EmulatedFakeCamera3.cpp
@@ -1109,7 +1109,7 @@
         mCapabilities.add(FULL_LEVEL);
         // "RAW" causes several CTS failures: b/68723953, disable it so far.
         // TODO: add "RAW" back when all failures are resolved.
-        //mCapabilities.add(RAW);
+        mCapabilities.add(RAW);
         mCapabilities.add(MOTION_TRACKING);
     }
 
@@ -1330,7 +1330,7 @@
 
     // android.flash
 
-    static const uint8_t flashAvailable = 0;
+    static const uint8_t flashAvailable = 1;
     ADD_STATIC_ENTRY(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1);
 
     // android.hotPixel
diff --git a/camera/JpegCompressor.cpp b/camera/JpegCompressor.cpp
index 3a5b15e..168b98a 100644
--- a/camera/JpegCompressor.cpp
+++ b/camera/JpegCompressor.cpp
@@ -46,7 +46,7 @@
 
 NV21JpegCompressor::NV21JpegCompressor()
 {
-    const char dlName[] = "/vendor/lib/hw/camera.goldfish.jpeg.so";
+    const char dlName[] = "/vendor/lib/hw/camera.ranchu.jpeg.so";
     if (mDl == NULL) {
         mDl = dlopen(dlName, RTLD_NOW);
     }
diff --git a/camera/media_codecs.xml b/camera/media_codecs.xml
index edead34..81cffc9 100644
--- a/camera/media_codecs.xml
+++ b/camera/media_codecs.xml
@@ -82,6 +82,16 @@
         <Setting name="max-video-encoder-input-buffers" value="12" />
     </Settings>
 
+    <MediaCodec name="OMX.android.goldfish.h264.decoder" type="video/avc" >
+        <Limit name="concurrent-instances" max="4" />
+    </MediaCodec>
+    <MediaCodec name="OMX.android.goldfish.vp8.decoder" type="video/x-vnd.on2.vp8" >
+        <Limit name="concurrent-instances" max="4" />
+    </MediaCodec>
+    <MediaCodec name="OMX.android.goldfish.vp9.decoder" type="video/x-vnd.on2.vp9" >
+        <Limit name="concurrent-instances" max="4" />
+    </MediaCodec>
+
     <Include href="media_codecs_google_audio.xml" />
     <Include href="media_codecs_google_telephony.xml" />
     <Include href="media_codecs_google_video.xml" />
diff --git a/camera/media_codecs_google_video_default.xml b/camera/media_codecs_google_video_default.xml
index 3d95548..588ead5 100644
--- a/camera/media_codecs_google_video_default.xml
+++ b/camera/media_codecs_google_video_default.xml
@@ -36,37 +36,18 @@
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="OMX.android.goldfish.h264.decoder" type="video/avc">
-            <Limit name="size" min="96x96" max="2560x2560" />
+            <Limit name="size" min="96x96" max="3840x2160" />
             <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
             <Limit name="blocks-per-second" range="24-2073600" />
             <Limit name="bitrate" range="1-120000000" />
             <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
-            <Limit name="measured-frame-rate-320x240" range="183-183" />
-            <Limit name="measured-frame-rate-720x480" range="181-181" />
-            <Limit name="measured-frame-rate-1280x720" range="182-184" />
-            <Limit name="measured-frame-rate-1920x1080" range="30-50" />
-            <Limit name="measured-frame-rate-2560x1440" range="30-40" />
-            <Feature name="adaptive-playback" />
-        </MediaCodec>
-        <MediaCodec name="OMX.google.goldfish.h264.decoder" type="video/avc">
-            <Limit name="size" min="96x96" max="2560x2560" />
-            <Limit name="alignment" value="2x2" />
-            <Limit name="block-size" value="16x16" />
-            <Limit name="blocks-per-second" range="24-2073600" />
-            <Limit name="bitrate" range="1-120000000" />
-            <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
-            <Limit name="measured-frame-rate-320x240" range="183-183" />
-            <Limit name="measured-frame-rate-720x480" range="181-181" />
-            <Limit name="measured-frame-rate-1280x720" range="182-184" />
-            <Limit name="measured-frame-rate-1920x1080" range="30-50" />
-            <Limit name="measured-frame-rate-2560x1440" range="30-40" />
+            <Limit name="performance-point-3840x2160" value="60" />
+            <Limit name="measured-frame-rate-320x240" range="257-266" />
+            <Limit name="measured-frame-rate-720x480" range="262-264" />
+            <Limit name="measured-frame-rate-1280x720" range="227-251" />
+            <Limit name="measured-frame-rate-1920x1080" range="235-247" />
+            <Limit name="measured-frame-rate-3840x2160" range="235-247" />
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="OMX.google.h264.decoder" type="video/avc">
@@ -77,9 +58,7 @@
             <Limit name="bitrate" range="1-120000000" />
             <Limit name="frame-rate" range="1-480" />
             <Limit name="concurrent-instances" max="16" />
-            <Limit name="performance-point-720x480" range="180" />
-            <Limit name="performance-point-1280x720" value="480" />
-            <Limit name="performance-point-1920x1080" value="30" />
+            <Limit name="performance-point-1920x1088" value="30" />
             <Limit name="measured-frame-rate-320x240" range="183-183" />
             <Limit name="measured-frame-rate-720x480" range="181-181" />
             <Limit name="measured-frame-rate-1280x720" range="182-184" />
@@ -98,71 +77,33 @@
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="OMX.android.goldfish.vp9.decoder" type="video/x-vnd.on2.vp9">
-            <Limit name="size" min="96x96" max="3840x2150" />
+            <Limit name="size" min="96x96" max="3840x2160" />
             <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
             <Limit name="blocks-per-second" min="24" max="2073600" />
             <Limit name="bitrate" range="1-120000000" />
             <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
-            <Limit name="measured-frame-rate-320x240" range="183-183" />
-            <Limit name="measured-frame-rate-720x480" range="181-181" />
-            <Limit name="measured-frame-rate-1280x720" range="182-184" />
-            <Limit name="measured-frame-rate-1920x1088" range="30-50" />
-            <Limit name="measured-frame-rate-2560x1440" range="30-40" />
+            <Limit name="performance-point-3840x2160" value="60" />
+            <Limit name="measured-frame-rate-320x180" range="237-258" />
+            <Limit name="measured-frame-rate-640x360" range="237-258" />
+            <Limit name="measured-frame-rate-1280x720" range="237-258" />
+            <Limit name="measured-frame-rate-1920x1080" range="293-302" />
+            <Limit name="measured-frame-rate-3840x2160" range="150-150" />
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="OMX.android.goldfish.vp8.decoder" type="video/x-vnd.on2.vp8">
-            <Limit name="size" min="96x96" max="3840x2150" />
+            <Limit name="size" min="96x96" max="3840x2160" />
             <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
             <Limit name="blocks-per-second" min="24" max="2073600" />
             <Limit name="bitrate" range="1-120000000" />
             <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
-            <Limit name="measured-frame-rate-320x240" range="183-183" />
-            <Limit name="measured-frame-rate-720x480" range="181-181" />
-            <Limit name="measured-frame-rate-1280x720" range="182-184" />
-            <Limit name="measured-frame-rate-1920x1088" range="30-50" />
-            <Limit name="measured-frame-rate-2560x1440" range="30-40" />
-            <Feature name="adaptive-playback" />
-        </MediaCodec>
-        <MediaCodec name="OMX.google.goldfish.vp8.decoder" type="video/x-vnd.on2.vp8">
-            <Limit name="size" min="2x2" max="2560x2560" />
-            <Limit name="alignment" value="2x2" />
-            <Limit name="block-size" value="16x16" />
-            <Limit name="blocks-per-second" min="24" max="2073600" />
-            <Limit name="bitrate" range="1-120000000" />
-            <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
-            <Limit name="measured-frame-rate-320x240" range="183-183" />
-            <Limit name="measured-frame-rate-720x480" range="181-181" />
-            <Limit name="measured-frame-rate-1280x720" range="182-184" />
-            <Limit name="measured-frame-rate-1920x1088" range="30-50" />
-            <Limit name="measured-frame-rate-2560x1440" range="30-40" />
-            <Feature name="adaptive-playback" />
-        </MediaCodec>
-        <MediaCodec name="OMX.google.goldfish.vp9.decoder" type="video/x-vnd.on2.vp9">
-            <Limit name="size" min="2x2" max="2560x2560" />
-            <Limit name="alignment" value="2x2" />
-            <Limit name="block-size" value="16x16" />
-            <Limit name="blocks-per-second" min="24" max="2073600" />
-            <Limit name="bitrate" range="1-120000000" />
-            <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
-            <Limit name="measured-frame-rate-320x240" range="183-183" />
-            <Limit name="measured-frame-rate-720x480" range="181-181" />
-            <Limit name="measured-frame-rate-1280x720" range="182-184" />
-            <Limit name="measured-frame-rate-1920x1088" range="30-50" />
-            <Limit name="measured-frame-rate-2560x1440" range="30-40" />
+            <Limit name="performance-point-3840x2160" value="60" />
+            <Limit name="measured-frame-rate-320x180" range="743-817" />
+            <Limit name="measured-frame-rate-640x360" range="237-258" />
+            <Limit name="measured-frame-rate-1280x720" range="237-258" />
+            <Limit name="measured-frame-rate-1920x1080" range="30-160" />
+            <Limit name="measured-frame-rate-3840x2160" range="30-90" />
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="OMX.google.vp8.decoder" type="video/x-vnd.on2.vp8">
@@ -172,9 +113,7 @@
             <Limit name="blocks-per-second" min="24" max="2073600" />
             <Limit name="bitrate" range="1-120000000" />
             <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
+            <Limit name="performance-point-1920x1088" value="60" />
             <Limit name="measured-frame-rate-320x240" range="183-183" />
             <Limit name="measured-frame-rate-720x480" range="181-181" />
             <Limit name="measured-frame-rate-1280x720" range="182-184" />
@@ -189,12 +128,10 @@
             <Limit name="blocks-per-second" min="24" max="2073600" />
             <Limit name="bitrate" range="1-120000000" />
             <Limit name="frame-rate" range="1-480" />
-            <Limit name="performance-point-2560x1440" value="80" />
-            <Limit name="performance-point-1920x1080" value="160" />
-            <Limit name="performance-point-1280x720" value="480" />
+            <Limit name="performance-point-1920x1088" value="60" />
             <Limit name="measured-frame-rate-320x240" range="183-183" />
             <Limit name="measured-frame-rate-720x480" range="181-181" />
-            <Limit name="measured-frame-rate-1280x720" range="182-184" />
+            <Limit name="measured-frame-rate-1280x720" range="121-125" />
             <Limit name="measured-frame-rate-1920x1088" range="30-50" />
             <Limit name="measured-frame-rate-2560x1440" range="30-40" />
             <Feature name="adaptive-playback" />
diff --git a/data/etc/advancedFeatures.ini b/data/etc/advancedFeatures.ini
index 92c3774..73a8fc2 100644
--- a/data/etc/advancedFeatures.ini
+++ b/data/etc/advancedFeatures.ini
@@ -10,6 +10,7 @@
 RefCountPipe = on
 VirtioInput = on
 DynamicPartition = on
+HardwareDecoder = on
 YUVCache = on
 GLDirectMem = on
 Vulkan = on
diff --git a/data/etc/config.ini.xl b/data/etc/config.ini.xl
index 40ec7cc..32d2665 100644
--- a/data/etc/config.ini.xl
+++ b/data/etc/config.ini.xl
@@ -16,5 +16,5 @@
 image.sysdir.1=x86/
 skin.dynamic=no
 hw.lcd.density=560
-skin.name=1440x2560
-skin.path=1440x2560
+skin.name=1440x2960
+skin.path=1440x2960
diff --git a/data/etc/google/user/advancedFeatures.ini b/data/etc/google/user/advancedFeatures.ini
index 4b7cb33..85b5c3a 100644
--- a/data/etc/google/user/advancedFeatures.ini
+++ b/data/etc/google/user/advancedFeatures.ini
@@ -11,6 +11,7 @@
 RefCountPipe = on
 VirtioInput = on
 DynamicPartition = on
+HardwareDecoder = on
 MultiDisplay = on
 YUVCache = on
 GLDirectMem = on
diff --git a/data/etc/google/userdebug/advancedFeatures.ini b/data/etc/google/userdebug/advancedFeatures.ini
index 4b7cb33..85b5c3a 100644
--- a/data/etc/google/userdebug/advancedFeatures.ini
+++ b/data/etc/google/userdebug/advancedFeatures.ini
@@ -11,6 +11,7 @@
 RefCountPipe = on
 VirtioInput = on
 DynamicPartition = on
+HardwareDecoder = on
 MultiDisplay = on
 YUVCache = on
 GLDirectMem = on
diff --git a/emulator-info.txt b/emulator-info.txt
index 1ae560d..fb45a7e 100644
--- a/emulator-info.txt
+++ b/emulator-info.txt
@@ -1,2 +1,2 @@
 # Emulator (stable) version
-require version-emulator=6278574
+require version-emulator=6629878
diff --git a/rro_overlays/TetheringOverlay/Android.bp b/rro_overlays/TetheringOverlay/Android.bp
new file mode 100644
index 0000000..31b0c57
--- /dev/null
+++ b/rro_overlays/TetheringOverlay/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2020 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+runtime_resource_overlay {
+    name: "EmulatorTetheringConfigOverlay",
+    resource_dirs: ["res"],
+    product_specific: true,
+    sdk_version: "current",
+}
diff --git a/rro_overlays/TetheringOverlay/AndroidManifest.xml b/rro_overlays/TetheringOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..fc8c8bd
--- /dev/null
+++ b/rro_overlays/TetheringOverlay/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.networkstack.tethering.emulator"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application android:hasCode="false" />
+    <overlay
+      android:targetPackage="com.android.networkstack.tethering"
+      android:targetName="TetheringConfig"
+      android:isStatic="true"
+      android:priority="0"/>
+</manifest>
diff --git a/rro_overlays/TetheringOverlay/res/values/config.xml b/rro_overlays/TetheringOverlay/res/values/config.xml
new file mode 100644
index 0000000..8cb8b40
--- /dev/null
+++ b/rro_overlays/TetheringOverlay/res/values/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Allow testing SoftAP using the simulated interfaces on the emulator. -->
+    <string-array name="config_tether_wifi_regexs">
+      <item>"wlan\\d"</item>
+    </string-array>
+    <string-array name="config_tether_wifi_p2p_regexs">
+      <item>"p2p-wlan\\d-.*"</item>
+    </string-array>
+</resources>
diff --git a/sensors/multihal_sensors.cpp b/sensors/multihal_sensors.cpp
index 3502add..104ff7f 100644
--- a/sensors/multihal_sensors.cpp
+++ b/sensors/multihal_sensors.cpp
@@ -26,7 +26,9 @@
 using ahs10::SensorFlagBits;
 using ahs10::MetaDataEventType;
 
-MultihalSensors::MultihalSensors() : m_qemuSensorsFd(qemud_channel_open("sensors")) {
+MultihalSensors::MultihalSensors()
+        : m_qemuSensorsFd(qemud_channel_open("sensors"))
+        , m_batchInfo(getSensorNumber()) {
     if (!m_qemuSensorsFd.ok()) {
         ALOGE("%s:%d: m_qemuSensorsFd is not opened", __func__, __LINE__);
         ::abort();
@@ -56,13 +58,16 @@
         ::abort();
     }
     buffer[len] = 0;
-    uint32_t availableSensorsMask = 0;
-    if (sscanf(buffer, "%u", &availableSensorsMask) != 1) {
+    uint32_t hostSensorsMask = 0;
+    if (sscanf(buffer, "%u", &hostSensorsMask) != 1) {
         ALOGE("%s:%d: Can't parse qemud response", __func__, __LINE__);
         ::abort();
     }
     m_availableSensorsMask =
-        availableSensorsMask & ((1u << getSensorNumber()) - 1);
+        hostSensorsMask & ((1u << getSensorNumber()) - 1);
+
+    ALOGI("%s:%d: host sensors mask=%x, available sensors mask=%x",
+          __func__, __LINE__, hostSensorsMask, m_availableSensorsMask);
 
     if (!::android::base::Socketpair(AF_LOCAL, SOCK_STREAM, 0,
                                      &m_callersFd, &m_sensorThreadFd)) {
@@ -70,11 +75,17 @@
         ::abort();
     }
 
-    m_sensorThread = std::thread(qemuSensorListenerThreadStart, this);
+    m_sensorThread = std::thread(&MultihalSensors::qemuSensorListenerThread, this);
+    m_batchThread = std::thread(&MultihalSensors::batchThread, this);
 }
 
 MultihalSensors::~MultihalSensors() {
-    disableAllSensors();
+    setAllQemuSensors(false);
+
+    m_batchRunning = false;
+    m_batchUpdated.notify_one();
+    m_batchThread.join();
+
     qemuSensorThreadSendCommand(kCMD_QUIT);
     m_sensorThread.join();
 }
@@ -104,7 +115,7 @@
 }
 
 Return<Result> MultihalSensors::setOperationMode(const OperationMode mode) {
-    std::unique_lock<std::mutex> lock(m_apiMtx);
+    std::unique_lock<std::mutex> lock(m_mtx);
 
     if (m_activeSensorsMask) {
         return Result::INVALID_OPERATION;
@@ -120,25 +131,31 @@
         return Result::BAD_VALUE;
     }
 
-    std::unique_lock<std::mutex> lock(m_apiMtx);
+    std::unique_lock<std::mutex> lock(m_mtx);
+    BatchInfo& batchInfo = m_batchInfo[sensorHandle];
 
-    uint32_t newActiveMask;
     if (enabled) {
-        newActiveMask = m_activeSensorsMask | (1u << sensorHandle);
-    } else {
-        newActiveMask = m_activeSensorsMask & ~(1u << sensorHandle);
-    }
-    if (m_activeSensorsMask == newActiveMask) {
-        return Result::OK;
-    }
+        const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
+        LOG_ALWAYS_FATAL_IF(!sensor);
+        if (!(sensor->flags & static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE))) {
+            if (batchInfo.samplingPeriodNs <= 0) {
+                return Result::BAD_VALUE;
+            }
 
-    if (m_opMode == OperationMode::NORMAL) {
-        if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), sensorHandle, enabled)) {
-            return Result::INVALID_OPERATION;
+            BatchEventRef batchEventRef;
+            batchEventRef.timestamp =
+                ::android::elapsedRealtimeNano() + batchInfo.samplingPeriodNs;
+            batchEventRef.sensorHandle = sensorHandle;
+            batchEventRef.generation = ++batchInfo.generation;
+
+            m_batchQueue.push(batchEventRef);
+            m_batchUpdated.notify_one();
         }
-    }
 
-    m_activeSensorsMask = newActiveMask;
+        m_activeSensorsMask = m_activeSensorsMask | (1u << sensorHandle);
+    } else {
+        m_activeSensorsMask = m_activeSensorsMask & ~(1u << sensorHandle);
+    }
     return Result::OK;
 }
 
@@ -147,26 +164,35 @@
                                       const int64_t maxReportLatencyNs) {
     (void)maxReportLatencyNs;
 
-    const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
-    if (sensor) {
-        if (samplingPeriodNs >= sensor->minDelay) {
-            return Result::OK;
-        } else {
-            return Result::BAD_VALUE;
-        }
-    } else {
+    if (!isSensorHandleValid(sensorHandle)) {
         return Result::BAD_VALUE;
     }
+
+    const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
+    LOG_ALWAYS_FATAL_IF(!sensor);
+
+    if (samplingPeriodNs < sensor->minDelay) {
+        return Result::BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(m_mtx);
+    if (m_opMode == OperationMode::NORMAL) {
+        m_batchInfo[sensorHandle].samplingPeriodNs = samplingPeriodNs;
+    }
+
+    return Result::OK;
 }
 
 Return<Result> MultihalSensors::flush(const int32_t sensorHandle) {
-    const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
-    if (!sensor) {
+    if (!isSensorHandleValid(sensorHandle)) {
         return Result::BAD_VALUE;
     }
 
-    std::unique_lock<std::mutex> lock(m_apiMtx);
-    if (!(m_activeSensorsMask & (1u << sensorHandle))) {
+    const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
+    LOG_ALWAYS_FATAL_IF(!sensor);
+
+    std::unique_lock<std::mutex> lock(m_mtx);
+    if (!isSensorActive(sensorHandle)) {
         return Result::BAD_VALUE;
     }
 
@@ -175,48 +201,58 @@
     event.sensorType = SensorType::META_DATA;
     event.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
 
-    postSensorEventLocked(event);
+    doPostSensorEventLocked(*sensor, event);
     return Result::OK;
 }
 
 Return<Result> MultihalSensors::injectSensorData_2_1(const Event& event) {
+    if (!isSensorHandleValid(event.sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
     if (event.sensorType == SensorType::ADDITIONAL_INFO) {
         return Result::OK;
     }
 
-    std::unique_lock<std::mutex> lock(m_apiMtx);
+    std::unique_lock<std::mutex> lock(m_mtx);
     if (m_opMode != OperationMode::DATA_INJECTION) {
         return Result::INVALID_OPERATION;
     }
     const SensorInfo* sensor = getSensorInfoByHandle(event.sensorHandle);
-    if (!sensor) {
-        return Result::BAD_VALUE;
-    }
+    LOG_ALWAYS_FATAL_IF(!sensor);
     if (sensor->type != event.sensorType) {
         return Result::BAD_VALUE;
     }
 
-    postSensorEventLocked(event);
+    doPostSensorEventLocked(*sensor, event);
     return Result::OK;
 }
 
 Return<Result> MultihalSensors::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
-    std::unique_lock<std::mutex> lock(m_apiMtx);
-    disableAllSensors();
+    std::unique_lock<std::mutex> lock(m_mtx);
+    setAllQemuSensors(true);   // we need to start sampling sensors for batching
     m_opMode = OperationMode::NORMAL;
     m_halProxyCallback = halProxyCallback;
     return Result::OK;
 }
 
 void MultihalSensors::postSensorEvent(const Event& event) {
-    std::unique_lock<std::mutex> lock(m_apiMtx);
-    postSensorEventLocked(event);
+    const SensorInfo* sensor = getSensorInfoByHandle(event.sensorHandle);
+    LOG_ALWAYS_FATAL_IF(!sensor);
+
+    std::unique_lock<std::mutex> lock(m_mtx);
+    if (sensor->flags & static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE)) {
+        if (isSensorActive(event.sensorHandle)) {
+            doPostSensorEventLocked(*sensor, event);
+        }
+    } else {    // CONTINUOUS_MODE
+        m_batchInfo[event.sensorHandle].event = event;
+    }
 }
 
-void MultihalSensors::postSensorEventLocked(const Event& event) {
+void MultihalSensors::doPostSensorEventLocked(const SensorInfo& sensor,
+                                              const Event& event) {
     const bool isWakeupEvent =
-        getSensorInfoByHandle(event.sensorHandle)->flags &
-        static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+        sensor.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
 
     m_halProxyCallback->postEvents(
         {event},
@@ -227,6 +263,65 @@
     return TEMP_FAILURE_RETRY(write(m_callersFd.get(), &cmd, 1)) == 1;
 }
 
+bool MultihalSensors::isSensorHandleValid(int sensorHandle) const {
+    if (!goldfish::isSensorHandleValid(sensorHandle)) {
+        return false;
+    }
+
+    if (!(m_availableSensorsMask & (1u << sensorHandle))) {
+        return false;
+    }
+
+    return true;
+}
+
+void MultihalSensors::batchThread() {
+    using high_resolution_clock = std::chrono::high_resolution_clock;
+
+    while (m_batchRunning) {
+        std::unique_lock<std::mutex> lock(m_mtx);
+        if (m_batchQueue.empty()) {
+            m_batchUpdated.wait(lock);
+        } else {
+            const int64_t t = m_batchQueue.top().timestamp;
+            const auto d = std::chrono::nanoseconds(t);
+            high_resolution_clock::time_point waitUntil(d);
+            m_batchUpdated.wait_until(lock, waitUntil);
+        }
+
+        const int64_t nowNs = ::android::elapsedRealtimeNano();
+        while (!m_batchQueue.empty() && (nowNs >= m_batchQueue.top().timestamp)) {
+            BatchEventRef evRef = m_batchQueue.top();
+            m_batchQueue.pop();
+
+            const int sensorHandle = evRef.sensorHandle;
+            LOG_ALWAYS_FATAL_IF(!goldfish::isSensorHandleValid(sensorHandle));
+            if (!isSensorActive(sensorHandle)) {
+                continue;
+            }
+
+            BatchInfo &batchInfo = m_batchInfo[sensorHandle];
+            if (batchInfo.event.sensorType == SensorType::META_DATA) {
+                ALOGW("%s:%d the host has not provided value yet for sensorHandle=%d",
+                      __func__, __LINE__, sensorHandle);
+            } else {
+                batchInfo.event.timestamp = evRef.timestamp;
+                const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
+                LOG_ALWAYS_FATAL_IF(!sensor);
+                doPostSensorEventLocked(*sensor, batchInfo.event);
+            }
+
+            if (evRef.generation == batchInfo.generation) {
+                const int64_t samplingPeriodNs = batchInfo.samplingPeriodNs;
+                LOG_ALWAYS_FATAL_IF(samplingPeriodNs <= 0);
+
+                evRef.timestamp += samplingPeriodNs;
+                m_batchQueue.push(evRef);
+            }
+        }
+    }
+}
+
 /// not supported //////////////////////////////////////////////////////////////
 Return<void> MultihalSensors::registerDirectChannel(const SharedMemInfo& mem,
                                                     registerDirectChannel_cb _hidl_cb) {
diff --git a/sensors/multihal_sensors.h b/sensors/multihal_sensors.h
index 80ed6a3..382af7f 100644
--- a/sensors/multihal_sensors.h
+++ b/sensors/multihal_sensors.h
@@ -17,8 +17,12 @@
 #pragma once
 #include <android-base/unique_fd.h>
 #include <V2_1/SubHal.h>
+#include <atomic>
+#include <condition_variable>
 #include <cstdint>
+#include <queue>
 #include <thread>
+#include <vector>
 
 namespace goldfish {
 namespace ahs = ::android::hardware::sensors;
@@ -26,6 +30,7 @@
 namespace ahs10 = ahs::V1_0;
 
 using ahs21::implementation::IHalProxyCallback;
+using ahs21::SensorInfo;
 using ahs21::Event;
 using ahs10::OperationMode;
 using ahs10::RateLevel;
@@ -81,14 +86,18 @@
         float lastHingeAngle2Value = kSensorNoValue;
     };
 
+    bool isSensorHandleValid(int sensorHandle) const;
+    bool isSensorActive(int sensorHandle) const {
+        return m_activeSensorsMask & (1u << sensorHandle);  // m_mtx required
+    }
     static bool activateQemuSensorImpl(int pipe, int sensorHandle, bool enabled);
-    bool disableAllSensors();
+    bool setAllQemuSensors(bool enabled);
     void parseQemuSensorEvent(const int pipe, QemuSensorsProtocolState* state);
     void postSensorEvent(const Event& event);
-    void postSensorEventLocked(const Event& event);
+    void doPostSensorEventLocked(const SensorInfo& sensor, const Event& event);
 
     void qemuSensorListenerThread();
-    static void qemuSensorListenerThreadStart(MultihalSensors* that);
+    void batchThread();
 
     static constexpr char kCMD_QUIT = 'q';
     bool qemuSensorThreadSendCommand(char cmd) const;
@@ -105,7 +114,32 @@
     uint32_t                m_activeSensorsMask = 0;
     OperationMode           m_opMode = OperationMode::NORMAL;
     sp<IHalProxyCallback>   m_halProxyCallback;
-    mutable std::mutex      m_apiMtx;
+
+    // batching
+    struct BatchEventRef {
+        int64_t  timestamp = -1;
+        int      sensorHandle = -1;
+        int      generation = 0;
+
+        bool operator<(const BatchEventRef &rhs) const {
+            // not a typo, we want m_batchQueue.top() to be the smallest timestamp
+            return timestamp > rhs.timestamp;
+        }
+    };
+
+    struct BatchInfo {
+        Event       event;
+        int64_t     samplingPeriodNs = 0;
+        int         generation = 0;
+    };
+
+    std::priority_queue<BatchEventRef>      m_batchQueue;
+    std::vector<BatchInfo>                  m_batchInfo;
+    std::condition_variable                 m_batchUpdated;
+    std::thread                             m_batchThread;
+    std::atomic<bool>                       m_batchRunning = true;
+
+    mutable std::mutex                      m_mtx;
 };
 
 }  // namespace goldfish
diff --git a/sensors/multihal_sensors_epoll.cpp b/sensors/multihal_sensors_epoll.cpp
index 0be1224..cf2ae56 100644
--- a/sensors/multihal_sensors_epoll.cpp
+++ b/sensors/multihal_sensors_epoll.cpp
@@ -38,10 +38,6 @@
 }
 }  // namespace
 
-void MultihalSensors::qemuSensorListenerThreadStart(MultihalSensors* that) {
-    that->qemuSensorListenerThread();
-}
-
 void MultihalSensors::qemuSensorListenerThread() {
     const unique_fd epollFd(epoll_create1(0));
     if (!epollFd.ok()) {
diff --git a/sensors/multihal_sensors_qemu.cpp b/sensors/multihal_sensors_qemu.cpp
index a07d569..f5da3a1 100644
--- a/sensors/multihal_sensors_qemu.cpp
+++ b/sensors/multihal_sensors_qemu.cpp
@@ -69,19 +69,16 @@
     }
 }
 
-bool MultihalSensors::disableAllSensors() {
-    if (m_opMode == OperationMode::NORMAL) {
-        uint32_t mask = m_activeSensorsMask;
-        for (int i = 0; mask; ++i, mask >>= 1) {
-            if (mask & 1) {
-                if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), i, false)) {
-                    return false;
-                }
+bool MultihalSensors::setAllQemuSensors(const bool enabled) {
+    uint32_t mask = m_availableSensorsMask;
+    for (int i = 0; mask; ++i, mask >>= 1) {
+        if (mask & 1) {
+            if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), i, enabled)) {
+                return false;
             }
         }
     }
 
-    m_activeSensorsMask = 0;
     return true;
 }
 
diff --git a/sensors/sensor_list.cpp b/sensors/sensor_list.cpp
index 245379f..d228ba6 100644
--- a/sensors/sensor_list.cpp
+++ b/sensors/sensor_list.cpp
@@ -122,11 +122,11 @@
         .maxRange = 80.0,
         .resolution = 1.0,
         .power = 0.0,
-        .minDelay = 10000,
+        .minDelay = 0,
         .fifoReservedEventCount = 0,
         .fifoMaxEventCount = 0,
         .requiredPermission = "",
-        .maxDelay = 500000,
+        .maxDelay = 0,
         .flags = SensorFlagBits::DATA_INJECTION |
                  SensorFlagBits::ON_CHANGE_MODE
     },
@@ -140,11 +140,11 @@
         .maxRange = 1.0,
         .resolution = 1.0,
         .power = 20.0,
-        .minDelay = 10000,
+        .minDelay = 0,
         .fifoReservedEventCount = 0,
         .fifoMaxEventCount = 0,
         .requiredPermission = "",
-        .maxDelay = 500000,
+        .maxDelay = 0,
         .flags = SensorFlagBits::DATA_INJECTION |
                  SensorFlagBits::ON_CHANGE_MODE |
                  SensorFlagBits::WAKE_UP
@@ -159,11 +159,11 @@
         .maxRange = 40000.0,
         .resolution = 1.0,
         .power = 20.0,
-        .minDelay = 10000,
+        .minDelay = 0,
         .fifoReservedEventCount = 0,
         .fifoMaxEventCount = 0,
         .requiredPermission = "",
-        .maxDelay = 500000,
+        .maxDelay = 0,
         .flags = SensorFlagBits::DATA_INJECTION |
                  SensorFlagBits::ON_CHANGE_MODE
     },
@@ -195,11 +195,11 @@
         .maxRange = 100.0,
         .resolution = 1.0,
         .power = 20.0,
-        .minDelay = 10000,
+        .minDelay = 0,
         .fifoReservedEventCount = 0,
         .fifoMaxEventCount = 0,
         .requiredPermission = "",
-        .maxDelay = 500000,
+        .maxDelay = 0,
         .flags = SensorFlagBits::DATA_INJECTION |
                  SensorFlagBits::ON_CHANGE_MODE
     },
@@ -248,11 +248,11 @@
         .maxRange = 360,
         .resolution = 1.0,
         .power = 3.0,
-        .minDelay = 10000,
+        .minDelay = 0,
         .fifoReservedEventCount = 0,
         .fifoMaxEventCount = 0,
         .requiredPermission = "",
-        .maxDelay = 500000,
+        .maxDelay = 0,
         .flags = SensorFlagBits::DATA_INJECTION |
                  SensorFlagBits::ON_CHANGE_MODE |
                  SensorFlagBits::WAKE_UP
@@ -267,11 +267,11 @@
         .maxRange = 360,
         .resolution = 1.0,
         .power = 3.0,
-        .minDelay = 10000,
+        .minDelay = 0,
         .fifoReservedEventCount = 0,
         .fifoMaxEventCount = 0,
         .requiredPermission = "",
-        .maxDelay = 500000,
+        .maxDelay = 0,
         .flags = SensorFlagBits::DATA_INJECTION |
                  SensorFlagBits::ON_CHANGE_MODE |
                  SensorFlagBits::WAKE_UP
@@ -286,11 +286,11 @@
         .maxRange = 360,
         .resolution = 1.0,
         .power = 3.0,
-        .minDelay = 10000,
+        .minDelay = 0,
         .fifoReservedEventCount = 0,
         .fifoMaxEventCount = 0,
         .requiredPermission = "",
-        .maxDelay = 500000,
+        .maxDelay = 0,
         .flags = SensorFlagBits::DATA_INJECTION |
                  SensorFlagBits::ON_CHANGE_MODE |
                  SensorFlagBits::WAKE_UP
diff --git a/sepolicy/common/file_contexts b/sepolicy/common/file_contexts
index 421952f..f009b7c 100644
--- a/sepolicy/common/file_contexts
+++ b/sepolicy/common/file_contexts
@@ -45,6 +45,7 @@
 /vendor/bin/hw/android\.hardware\.power\.stats@1\.0-service\.mock  u:object_r:hal_power_stats_default_exec:s0
 /vendor/bin/hw/android\.hardware\.gnss@2\.0-service\.ranchu        u:object_r:hal_gnss_default_exec:s0
 /vendor/bin/hw/android\.hardware\.neuralnetworks@1\.3-service-sample-.*   u:object_r:hal_neuralnetworks_sample_exec:s0
+/vendor/bin/hw/android\.hardware\.audio\.service.ranchu   u:object_r:hal_audio_default_exec:s0
 
 /vendor/lib(64)?/hw/vulkan\.ranchu\.so   u:object_r:same_process_hal_file:s0
 /vendor/lib(64)?/libEGL_emulation\.so          u:object_r:same_process_hal_file:s0
diff --git a/vendor.mk b/vendor.mk
index b65a9bb..4a58872 100644
--- a/vendor.mk
+++ b/vendor.mk
@@ -18,6 +18,9 @@
 #
 $(call inherit-product-if-exists, frameworks/native/build/phone-xhdpi-2048-dalvik-heap.mk)
 
+# Enable Scoped Storage related
+$(call inherit-product, $(SRC_TARGET_DIR)/product/emulated_storage.mk)
+
 PRODUCT_SOONG_NAMESPACES += \
     device/generic/goldfish \
     device/generic/goldfish-opengl
@@ -56,6 +59,7 @@
     local_time.default \
     SdkSetup \
     EmulatorRadioConfig \
+    EmulatorTetheringConfigOverlay \
     libstagefrighthw \
     libstagefright_goldfish_vpxdec \
     libstagefright_goldfish_avcdec \
@@ -73,11 +77,6 @@
 endif
 
 PRODUCT_PACKAGES += \
-    audio.r_submix.default \
-    android.hardware.audio.service \
-    android.hardware.audio.effect@6.0-impl:32
-
-PRODUCT_PACKAGES += \
     android.hardware.bluetooth@1.1-service.sim \
     android.hardware.bluetooth.audio@2.0-impl
 PRODUCT_PROPERTY_OVERRIDES += bt.rootcanal_test_console=off
@@ -151,15 +150,20 @@
 DEVICE_MANIFEST_FILE += device/generic/goldfish/manifest.camera.xml
 endif
 
-ifneq ($(EMULATOR_VENDOR_NO_SOUND_TRIGGER),true)
-PRODUCT_PACKAGES += android.hardware.soundtrigger@2.2-impl.ranchu
-endif
-
 ifneq ($(EMULATOR_VENDOR_NO_SOUND),true)
-PRODUCT_PACKAGES += android.hardware.audio@6.0-impl.ranchu
+PRODUCT_PACKAGES += \
+    android.hardware.audio.service.ranchu \
+    android.hardware.soundtrigger@2.2-impl.ranchu \
+    android.hardware.audio.effect@6.0-impl \
+
 PRODUCT_COPY_FILES += \
     device/generic/goldfish/audio/policy/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml \
-    device/generic/goldfish/audio/policy/primary_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/primary_audio_policy_configuration.xml
+    device/generic/goldfish/audio/policy/primary_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/primary_audio_policy_configuration.xml \
+    frameworks/av/services/audiopolicy/config/r_submix_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/r_submix_audio_policy_configuration.xml \
+    frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \
+    frameworks/av/services/audiopolicy/config/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml \
+    frameworks/av/media/libeffects/data/audio_effects.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_effects.xml \
+
 endif
 
 PRODUCT_PACKAGES += \
@@ -270,6 +274,7 @@
     frameworks/native/data/etc/android.hardware.bluetooth.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth.xml \
     system/bt/vendor_libs/test_vendor_lib/data/controller_properties.json:vendor/etc/bluetooth/controller_properties.json \
     frameworks/native/data/etc/android.hardware.wifi.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.xml \
+    frameworks/native/data/etc/android.hardware.wifi.passpoint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.passpoint.xml \
     frameworks/native/data/etc/android.hardware.wifi.direct.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.direct.xml \
     device/generic/goldfish/data/etc/handheld_core_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/handheld_core_hardware.xml \
     device/generic/goldfish/camera/media_profiles.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_V1_0.xml \
@@ -280,9 +285,11 @@
     device/generic/goldfish/camera/media_codecs_performance.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_performance.xml \
     frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml \
     frameworks/native/data/etc/android.hardware.camera.ar.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.ar.xml \
-    frameworks/native/data/etc/android.hardware.camera.autofocus.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.autofocus.xml \
+    frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.flash-autofocus.xml \
+    frameworks/native/data/etc/android.hardware.camera.concurrent.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.concurrent.xml \
     frameworks/native/data/etc/android.hardware.camera.front.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.front.xml \
     frameworks/native/data/etc/android.hardware.camera.full.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.full.xml \
+    frameworks/native/data/etc/android.hardware.camera.raw.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.raw.xml \
     frameworks/native/data/etc/android.hardware.fingerprint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.fingerprint.xml \
     frameworks/native/data/etc/android.hardware.vulkan.level-1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.level.xml \
     frameworks/native/data/etc/android.hardware.vulkan.compute-0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.compute.xml \
@@ -290,9 +297,6 @@
     device/generic/goldfish/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.vulkan.deqp.level-2019-03-01.xml \
     frameworks/native/data/etc/android.software.autofill.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.autofill.xml \
     frameworks/native/data/etc/android.software.verified_boot.xml:${TARGET_COPY_OUT_PRODUCT}/etc/permissions/android.software.verified_boot.xml \
-    frameworks/av/media/libeffects/data/audio_effects.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_effects.xml \
-    frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \
-    frameworks/av/services/audiopolicy/config/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml \
     device/generic/goldfish/data/etc/permissions/privapp-permissions-goldfish.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/privapp-permissions-goldfish.xml \
     hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_back.json:$(TARGET_COPY_OUT_VENDOR)/etc/config/emu_camera_back.json \
     hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_front.json:$(TARGET_COPY_OUT_VENDOR)/etc/config/emu_camera_front.json \
diff --git a/wifi/wifi_hal/Android.bp b/wifi/wifi_hal/Android.bp
index 88c1e30..6431003 100644
--- a/wifi/wifi_hal/Android.bp
+++ b/wifi/wifi_hal/Android.bp
@@ -28,6 +28,7 @@
         "wifi_hal.cpp",
     ],
     shared_libs: [
+        "libnl",
         "liblog",
         "libcutils",
         "libhardware_legacy",
diff --git a/wifi/wifi_hal/interface.cpp b/wifi/wifi_hal/interface.cpp
index 7c683e5..47d8154 100644
--- a/wifi/wifi_hal/interface.cpp
+++ b/wifi/wifi_hal/interface.cpp
@@ -86,6 +86,9 @@
     return WIFI_SUCCESS;
 }
 
+// Wifi legacy HAL implicitly assumes getLinkStats is blocking and
+// handler will be set to nullptr immediately after invocation.
+// Therefore, this function will wait until onLinkStatsReply is called.
 wifi_error Interface::getLinkStats(wifi_request_id requestId,
                                    wifi_stats_result_handler handler) {
     NetlinkMessage message(RTM_GETLINK, mNetlink.getSequenceNumber());
@@ -97,12 +100,21 @@
     info->ifi_flags = 0;
     info->ifi_change = 0xFFFFFFFF;
 
-    bool success = mNetlink.sendMessage(message,
-                                        std::bind(&Interface::onLinkStatsReply,
-                                                  this,
-                                                  requestId,
-                                                  handler,
-                                                  std::placeholders::_1));
+    std::condition_variable condition;
+    std::mutex mutex;
+    std::unique_lock<std::mutex> lock(mutex);
+    bool stopped = false;
+    auto callback = [this, requestId, &handler,
+        &mutex, &condition, &stopped] (const NetlinkMessage& message) {
+        stopped = true;
+        std::unique_lock<std::mutex> lock(mutex);
+        onLinkStatsReply(requestId, handler, message);
+        condition.notify_all();
+    };
+    bool success = mNetlink.sendMessage(message, callback);
+    while (!stopped) {
+        condition.wait(lock);
+    }
     return success ? WIFI_SUCCESS : WIFI_ERROR_UNKNOWN;
 }
 
diff --git a/wifi/wifi_hal/netlinkmessage.cpp b/wifi/wifi_hal/netlinkmessage.cpp
index baf5800..06bb743 100644
--- a/wifi/wifi_hal/netlinkmessage.cpp
+++ b/wifi/wifi_hal/netlinkmessage.cpp
@@ -22,6 +22,7 @@
 #include <linux/rtnetlink.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <netlink/msg.h>
 
 size_t getSpaceForMessageType(uint16_t type) {
     switch (type) {
@@ -51,13 +52,12 @@
 
 bool NetlinkMessage::getAttribute(int attributeId, void* data, size_t size) const {
     const void* value = nullptr;
-    uint16_t attrSize = 0;
-    if (!findAttribute(attributeId, &value, &attrSize)) {
+    const auto attr = nlmsg_find_attr((struct nlmsghdr*)mData.data(), sizeof(ifinfomsg), attributeId);
+    if (!attr) {
         return false;
     }
-    if (size > attrSize) {
-        return false;
-    }
+    value = (const uint8_t*) attr + NLA_HDRLEN;
+    size = attr->nla_len;
     memcpy(data, value, size);
     return true;
 }
@@ -71,30 +71,3 @@
     auto header = reinterpret_cast<const nlmsghdr*>(mData.data());
     return header->nlmsg_seq;
 }
-
-bool NetlinkMessage::findAttribute(int attributeId,
-                                   const void** value,
-                                   uint16_t* size) const {
-    const uint8_t* end = mData.data() + mData.size();
-    size_t attrOffset = getSpaceForMessageType(type());
-    if (attrOffset == 0) {
-        return false;
-    }
-    const uint8_t* attribute = mData.data() + attrOffset;
-    while (attribute < end) {
-        auto header = reinterpret_cast<const nlattr*>(attribute);
-        if (header->nla_len == 0) {
-            // The length should include the header so the length should always
-            // be greater than zero. If it doesn't we're going to end up looping
-            // forever so ignore this.
-            return false;
-        }
-        if (header->nla_type == attributeId) {
-            *value = attribute + NLA_HDRLEN;
-            *size = header->nla_len;
-            return true;
-        }
-        attribute += header->nla_len;
-    }
-    return false;
-}
diff --git a/wifi/wifi_hal/netlinkmessage.h b/wifi/wifi_hal/netlinkmessage.h
index 45fd7cd..5e1a3b8 100644
--- a/wifi/wifi_hal/netlinkmessage.h
+++ b/wifi/wifi_hal/netlinkmessage.h
@@ -60,9 +60,6 @@
     NetlinkMessage& operator=(const NetlinkMessage&) = delete;
 
     bool getAttribute(int attributeId, void* data, size_t size) const;
-    bool findAttribute(int attributeId,
-                       const void** value,
-                       uint16_t* size) const;
 
     std::vector<uint8_t> mData;
 };