Reduce warming up time to 3.5 seconds am: bb279e3a7b

Original change: https://googleplex-android-review.googlesource.com/c/device/generic/goldfish/+/19815484

Change-Id: Ic2a3b961c1cf3570f452ec36745491f8236e4af0
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/init.ranchu.rc b/init.ranchu.rc
index d2e5bde..9be9885 100644
--- a/init.ranchu.rc
+++ b/init.ranchu.rc
@@ -62,8 +62,7 @@
     setprop ro.opengles.version ${ro.kernel.qemu.opengles.version}
     setprop ro.zygote.disable_gl_preload 1
 
-    # 0: omx; 4: c2 default now
-    setprop debug.stagefright.ccodec 4
+    setprop debug.stagefright.ccodec 0
     setprop debug.stagefright.ccodec ${ro.kernel.qemu.media.ccodec}
 
     setprop dalvik.vm.heapsize 192m
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/vendor.mk b/vendor.mk
index 68338f7..4a58872 100644
--- a/vendor.mk
+++ b/vendor.mk
@@ -59,6 +59,7 @@
     local_time.default \
     SdkSetup \
     EmulatorRadioConfig \
+    EmulatorTetheringConfigOverlay \
     libstagefrighthw \
     libstagefright_goldfish_vpxdec \
     libstagefright_goldfish_avcdec \
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;
 };