Merge "Fix getActiveMicrophones vts failure."
diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
index a76770d..8217b94 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
@@ -9,3 +9,5 @@
     # and its .rc file has an "onrestart restart audio-hal" rule, thus
     # an additional auto-restart from the init process isn't needed.
     oneshot
+    interface android.hardware.audio@4.0::IDevicesFactory default
+    interface android.hardware.audio@2.0::IDevicesFactory default
diff --git a/automotive/README.md b/automotive/README.md
new file mode 100644
index 0000000..341a1bb
--- /dev/null
+++ b/automotive/README.md
@@ -0,0 +1,10 @@
+## Autmotive HALs ##
+---
+
+## Overview: ##
+
+The automotive HAL tree is used by Android Automotive to discover and
+operate hardware specific to a car.
+
+The HALs are not (yet) frozen, as the HAL definition is expected to evolve
+between Android releases.
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 22ab079..65e9133 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -64,6 +64,7 @@
         "impl/vhal_v2_0/SocketComm.cpp",
         "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
         "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
+        "impl/vhal_v2_0/GeneratorHub.cpp",
     ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["impl"],
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 4ae94c0..50f3622 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -32,6 +32,8 @@
 constexpr int ABS_ACTIVE = (int)VehicleProperty::ABS_ACTIVE;
 constexpr int AP_POWER_STATE_REQ = (int)VehicleProperty::AP_POWER_STATE_REQ;
 constexpr int AP_POWER_STATE_REPORT = (int)VehicleProperty::AP_POWER_STATE_REPORT;
+constexpr int DOOR_1_LEFT = (int)VehicleAreaDoor::ROW_1_LEFT;
+constexpr int DOOR_1_RIGHT = (int)VehicleAreaDoor::ROW_1_RIGHT;
 constexpr int OBD2_LIVE_FRAME = (int)VehicleProperty::OBD2_LIVE_FRAME;
 constexpr int OBD2_FREEZE_FRAME = (int)VehicleProperty::OBD2_FREEZE_FRAME;
 constexpr int OBD2_FREEZE_FRAME_INFO = (int)VehicleProperty::OBD2_FREEZE_FRAME_INFO;
@@ -68,33 +70,39 @@
 enum class FakeDataCommand : int32_t {
     /**
      * Starts linear fake data generation. Caller must provide additional data:
-     *     int32Values[1] - VehicleProperty to which command applies
+     *     int32Values[1] - vehicle property to which command applies
      *     int64Values[0] - periodic interval in nanoseconds
      *     floatValues[0] - initial value
      *     floatValues[1] - dispersion defines the min/max value relative to initial value, where
      *                      max = initial_value + dispersion, min = initial_value - dispersion.
      *                      Dispersion should be non-negative, otherwise the behavior is undefined.
      *     floatValues[2] - increment, with every timer tick the value will be incremented by this
-     *                      amount. When reaching to max value, the current value will be set to min.
-     *                      It should be non-negative, otherwise the behavior is undefined.
+     *                      amount. When reaching to max value, the current value will be set to
+     *                      min. It should be non-negative, otherwise the behavior is undefined.
      */
     StartLinear = 0,
 
-    /** Stops generating of fake data that was triggered by Start commands.
-     *     int32Values[1] - VehicleProperty to which command applies. VHAL will stop the
+    /** Stops linear fake data generation that was triggered by StartLinear commands.
+     *     int32Values[1] - vehicle property to which command applies. VHAL will stop the
      *                      corresponding linear generation for that property.
      */
     StopLinear = 1,
 
     /**
-     * Starts JSON-based fake data generation. Caller must provide a string value specifying
-     * the path to fake value JSON file:
+     * Starts JSON-based fake data generation. It iterates through JSON-encoded VHAL events from a
+     * file and inject them to VHAL. The iteration can be repeated multiple times or infinitely.
+     * Caller must provide additional data:
+     *     int32Values[1] - number of iterations. If it is not provided or -1. The iteration will be
+     *                      repeated infinite times.
      *     stringValue    - path to the fake values JSON file
      */
     StartJson = 2,
 
     /**
-     * Stops JSON-based fake data generation. No additional arguments needed.
+     * Stops JSON-based fake data generation. As multiple JSON-based generation can happen at the
+     * same time. Caller must provide the path of fake value JSON file to stop the corresponding
+     * generation:
+     *     stringValue    - path to the fake values JSON file
      */
     StopJson = 3,
 
@@ -440,13 +448,13 @@
             },
     },
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::DOOR_LOCK),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {1}}},
+    {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
+                .access = VehiclePropertyAccess::READ,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
+                                VehicleAreaConfig{.areaId = DOOR_1_RIGHT}}},
+     .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
+                           {DOOR_1_RIGHT, {.int32Values = {1}}}}},
 
     {.config =
          {
@@ -459,23 +467,15 @@
          },
      .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}},
 
-    {
-        .config =
-            {
-                .prop = ABS_ACTIVE,
+    {.config = {.prop = ABS_ACTIVE,
                 .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-            },
-    },
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+     .initialValue = {.int32Values = {0}}},
 
-    {
-        .config =
-            {
-                .prop = TRACTION_CONTROL_ACTIVE,
+    {.config = {.prop = TRACTION_CONTROL_ACTIVE,
                 .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-            },
-    },
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+     .initialValue = {.int32Values = {0}}},
 
     {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                 .access = VehiclePropertyAccess::READ,
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 07695bf..0e5897a 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -92,10 +92,8 @@
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
       mRecurrentTimer(
           std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
-      mLinearFakeValueGenerator(std::make_unique<LinearFakeValueGenerator>(
-          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))),
-      mJsonFakeValueGenerator(std::make_unique<JsonFakeValueGenerator>(
-          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))) {
+      mGeneratorHub(
+          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
     initStaticConfig();
     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
         mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -343,19 +341,54 @@
     switch (command) {
         case FakeDataCommand::StartLinear: {
             ALOGI("%s, FakeDataCommand::StartLinear", __func__);
-            return mLinearFakeValueGenerator->start(request);
+            if (v.int32Values.size() < 2) {
+                ALOGE("%s: expected property ID in int32Values", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            if (!v.int64Values.size()) {
+                ALOGE("%s: interval is not provided in int64Values", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            if (v.floatValues.size() < 3) {
+                ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
+                      v.floatValues.size());
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            mGeneratorHub.registerGenerator(cookie,
+                                            std::make_unique<LinearFakeValueGenerator>(request));
+            break;
         }
         case FakeDataCommand::StartJson: {
             ALOGI("%s, FakeDataCommand::StartJson", __func__);
-            return mJsonFakeValueGenerator->start(request);
+            if (v.stringValue.empty()) {
+                ALOGE("%s: path to JSON file is missing", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            mGeneratorHub.registerGenerator(cookie,
+                                            std::make_unique<JsonFakeValueGenerator>(request));
+            break;
         }
         case FakeDataCommand::StopLinear: {
             ALOGI("%s, FakeDataCommand::StopLinear", __func__);
-            return mLinearFakeValueGenerator->stop(request);
+            if (v.int32Values.size() < 2) {
+                ALOGE("%s: expected property ID in int32Values", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            mGeneratorHub.unregisterGenerator(cookie);
+            break;
         }
         case FakeDataCommand::StopJson: {
             ALOGI("%s, FakeDataCommand::StopJson", __func__);
-            return mJsonFakeValueGenerator->stop(request);
+            if (v.stringValue.empty()) {
+                ALOGE("%s: path to JSON file is missing", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            mGeneratorHub.unregisterGenerator(cookie);
+            break;
         }
         case FakeDataCommand::KeyPress: {
             ALOGI("%s, FakeDataCommand::KeyPress", __func__);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index c188aef..ec59690 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -30,8 +30,7 @@
 #include "vhal_v2_0/VehiclePropertyStore.h"
 
 #include "DefaultConfig.h"
-#include "FakeValueGenerator.h"
-
+#include "GeneratorHub.h"
 #include "VehicleEmulator.h"
 
 namespace android {
@@ -85,8 +84,7 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
-    std::unique_ptr<FakeValueGenerator> mLinearFakeValueGenerator;
-    std::unique_ptr<FakeValueGenerator> mJsonFakeValueGenerator;
+    GeneratorHub mGeneratorHub;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
index 1eeb88d..d6ad77d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
@@ -27,28 +27,22 @@
 
 namespace impl {
 
-using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
-using MuxGuard = std::lock_guard<std::mutex>;
-
 class FakeValueGenerator {
 public:
     virtual ~FakeValueGenerator() = default;
-    /**
-     * Starts generating VHAL events
-     *
-     * @param request in VehiclePropValue with required information to start fake data generation
-     * @return StatusCode of the start request
-     */
-    virtual StatusCode start(const VehiclePropValue& request) = 0;
-    /**
-     * Stops generating VHAL events
-     * @param request in VehiclePropValue with required information to stop fake data generation
-     * @return StatusCode of the stop request
-     */
-    virtual StatusCode stop(const VehiclePropValue& request) = 0;
+
+    virtual VehiclePropValue nextEvent() = 0;
+
+    virtual bool hasNext() = 0;
 };
 
-}  // impl
+using Clock = std::chrono::steady_clock;
+using Nanos = std::chrono::nanoseconds;
+using TimePoint = std::chrono::time_point<Clock, Nanos>;
+
+using FakeValueGeneratorPtr = std::unique_ptr<FakeValueGenerator>;
+
+}  // namespace impl
 
 }  // namespace V2_0
 }  // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
new file mode 100644
index 0000000..548285a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GeneratorHub"
+
+#include <log/log.h>
+
+#include "GeneratorHub.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+GeneratorHub::GeneratorHub(const OnHalEvent& onHalEvent)
+    : mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {}
+
+void GeneratorHub::registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator) {
+    {
+        std::lock_guard<std::mutex> g(mLock);
+        // Register only if the generator can produce event
+        if (generator->hasNext()) {
+            // Push the next event if it is a new generator
+            if (mGenerators.find(cookie) == mGenerators.end()) {
+                ALOGI("%s: Registering new generator, cookie: %d", __func__, cookie);
+                mEventQueue.push({cookie, generator->nextEvent()});
+            }
+            mGenerators[cookie] = std::move(generator);
+            ALOGI("%s: Registered generator, cookie: %d", __func__, cookie);
+        }
+    }
+    mCond.notify_one();
+}
+
+void GeneratorHub::unregisterGenerator(int32_t cookie) {
+    {
+        std::lock_guard<std::mutex> g(mLock);
+        mGenerators.erase(cookie);
+    }
+    mCond.notify_one();
+    ALOGI("%s: Unregistered generator, cookie: %d", __func__, cookie);
+}
+
+void GeneratorHub::run() {
+    while (true) {
+        std::unique_lock<std::mutex> g(mLock);
+        // Pop events whose generator does not exist (may be already unregistered)
+        while (!mEventQueue.empty()
+               && mGenerators.find(mEventQueue.top().cookie) == mGenerators.end()) {
+             mEventQueue.pop();
+        }
+        // Wait until event queue is not empty
+        mCond.wait(g, [this] { return !mEventQueue.empty(); });
+
+        const VhalEvent& curEvent = mEventQueue.top();
+
+        TimePoint eventTime(Nanos(curEvent.val.timestamp));
+        // Wait until the soonest event happen
+        if (mCond.wait_until(g, eventTime) != std::cv_status::timeout) {
+        // It is possible that a new generator is registered and produced a sooner event, or current
+        // generator is unregistered, in this case the thread will re-evaluate the soonest event
+            ALOGI("Something happened while waiting");
+            continue;
+        }
+        // Now it's time to handle current event.
+        mOnHalEvent(curEvent.val);
+        // Update queue by popping current event and producing next event from the same generator
+        int32_t cookie = curEvent.cookie;
+        mEventQueue.pop();
+        if (hasNext(cookie)) {
+            mEventQueue.push({cookie, mGenerators[cookie]->nextEvent()});
+        } else {
+            ALOGI("%s: Generator ended, unregister it, cookie: %d", __func__, cookie);
+            mGenerators.erase(cookie);
+        }
+    }
+}
+
+bool GeneratorHub::hasNext(int32_t cookie) {
+    return mGenerators.find(cookie) != mGenerators.end() && mGenerators[cookie]->hasNext();
+}
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
new file mode 100644
index 0000000..dcf6a4f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <iostream>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+
+#include "FakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * This is the scheduler for all VHAL event generators. It manages all generators and uses priority
+ * queue to maintain generated events ordered by timestamp. The scheduler uses a single thread to
+ * keep querying and updating the event queue to make sure events from all generators are produced
+ * in order.
+ */
+class GeneratorHub {
+private:
+    struct VhalEvent {
+        int32_t cookie;  // Cookie is used to find the associated generator.
+        VehiclePropValue val;
+    };
+    // Comparator used by priority queue to keep track of soonest event.
+    struct GreaterByTime {
+        bool operator()(const VhalEvent& lhs, const VhalEvent& rhs) const {
+            return lhs.val.timestamp > rhs.val.timestamp;
+        }
+    };
+
+    using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
+
+public:
+    GeneratorHub(const OnHalEvent& onHalEvent);
+    ~GeneratorHub() = default;
+
+    /**
+     * Register a new generator. The generator will be discarded if it could not produce next event.
+     * The existing generator will be overridden if it has the same cookie.
+     */
+    void registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator);
+
+    void unregisterGenerator(int32_t cookie);
+
+private:
+    /**
+     * Main loop of the single thread to producing event and updating event queue.
+     */
+    void run();
+
+    bool hasNext(int32_t cookie);
+
+private:
+    std::priority_queue<VhalEvent, std::vector<VhalEvent>, GreaterByTime> mEventQueue;
+    std::unordered_map<int32_t, FakeValueGeneratorPtr> mGenerators;
+    OnHalEvent mOnHalEvent;
+
+    mutable std::mutex mLock;
+    std::condition_variable mCond;
+    std::thread mThread;
+};
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
index 88b8f86..c293c0a 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -31,57 +31,48 @@
 
 namespace impl {
 
-JsonFakeValueGenerator::JsonFakeValueGenerator(const OnHalEvent& onHalEvent)
-    : mOnHalEvent(onHalEvent), mThread(&JsonFakeValueGenerator::loop, this) {}
-
-JsonFakeValueGenerator::~JsonFakeValueGenerator() {
-    mStopRequested = true;
-    {
-        MuxGuard g(mLock);
-        mGenCfg.index = 0;
-        mGenCfg.events.clear();
-    }
-    mCond.notify_one();
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-}
-
-StatusCode JsonFakeValueGenerator::start(const VehiclePropValue& request) {
+JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) {
     const auto& v = request.value;
-    if (v.stringValue.empty()) {
-        ALOGE("%s: path to JSON file is missing", __func__);
-        return StatusCode::INVALID_ARG;
-    }
     const char* file = v.stringValue.c_str();
     std::ifstream ifs(file);
     if (!ifs) {
         ALOGE("%s: couldn't open %s for parsing.", __func__, file);
-        return StatusCode::INTERNAL_ERROR;
     }
-    std::vector<VehiclePropValue> fakeVhalEvents = parseFakeValueJson(ifs);
-
-    {
-        MuxGuard g(mLock);
-        mGenCfg = {0, fakeVhalEvents};
-    }
-    mCond.notify_one();
-    return StatusCode::OK;
+    mGenCfg = {
+        .index = 0,
+        .events = parseFakeValueJson(ifs),
+    };
+    // Iterate infinitely if repetition number is not provided
+    mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1];
 }
 
-StatusCode JsonFakeValueGenerator::stop(const VehiclePropValue& request) {
-    const auto& v = request.value;
-    if (!v.stringValue.empty()) {
-        ALOGI("%s: %s", __func__, v.stringValue.c_str());
+VehiclePropValue JsonFakeValueGenerator::nextEvent() {
+    VehiclePropValue generatedValue;
+    if (!hasNext()) {
+        return generatedValue;
     }
+    TimePoint eventTime = Clock::now();
+    if (mGenCfg.index != 0) {
+        // All events (start from 2nd one) are supposed to happen in the future with a delay
+        // equals to the duration between previous and current event.
+        eventTime += Nanos(mGenCfg.events[mGenCfg.index].timestamp -
+                           mGenCfg.events[mGenCfg.index - 1].timestamp);
+    }
+    generatedValue = mGenCfg.events[mGenCfg.index];
+    generatedValue.timestamp = eventTime.time_since_epoch().count();
 
-    {
-        MuxGuard g(mLock);
+    mGenCfg.index++;
+    if (mGenCfg.index == mGenCfg.events.size()) {
         mGenCfg.index = 0;
-        mGenCfg.events.clear();
+        if (mNumOfIterations > 0) {
+            mNumOfIterations--;
+        }
     }
-    mCond.notify_one();
-    return StatusCode::OK;
+    return generatedValue;
+}
+
+bool JsonFakeValueGenerator::hasNext() {
+    return mNumOfIterations != 0 && mGenCfg.events.size() > 0;
 }
 
 std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) {
@@ -141,30 +132,6 @@
     return fakeVhalEvents;
 }
 
-void JsonFakeValueGenerator::loop() {
-    static constexpr auto kInvalidTime = TimePoint(Nanos::max());
-
-    while (!mStopRequested) {
-        auto nextEventTime = kInvalidTime;
-        {
-            MuxGuard g(mLock);
-            if (mGenCfg.index < mGenCfg.events.size()) {
-                mOnHalEvent(mGenCfg.events[mGenCfg.index]);
-            }
-            if (!mGenCfg.events.empty() && mGenCfg.index < mGenCfg.events.size() - 1) {
-                Nanos intervalNano =
-                    static_cast<Nanos>(mGenCfg.events[mGenCfg.index + 1].timestamp -
-                                       mGenCfg.events[mGenCfg.index].timestamp);
-                nextEventTime = Clock::now() + intervalNano;
-            }
-            mGenCfg.index++;
-        }
-
-        std::unique_lock<std::mutex> g(mLock);
-        mCond.wait_until(g, nextEventTime);
-    }
-}
-
 }  // namespace impl
 
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
index 51da4c5..43c8b9d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
@@ -17,11 +17,8 @@
 #ifndef android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_
 #define android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_
 
-#include <atomic>
 #include <chrono>
-#include <condition_variable>
 #include <iostream>
-#include <thread>
 
 #include <json/json.h>
 
@@ -37,32 +34,25 @@
 
 class JsonFakeValueGenerator : public FakeValueGenerator {
 private:
-    using Nanos = std::chrono::nanoseconds;
-    using Clock = std::chrono::steady_clock;
-    using TimePoint = std::chrono::time_point<Clock, Nanos>;
-
     struct GeneratorCfg {
         size_t index;
         std::vector<VehiclePropValue> events;
     };
 
 public:
-    JsonFakeValueGenerator(const OnHalEvent& onHalEvent);
-    ~JsonFakeValueGenerator();
-    StatusCode start(const VehiclePropValue& request) override;
-    StatusCode stop(const VehiclePropValue& request) override;
+    JsonFakeValueGenerator(const VehiclePropValue& request);
+    ~JsonFakeValueGenerator() = default;
+
+    VehiclePropValue nextEvent();
+
+    bool hasNext();
 
 private:
     std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is);
-    void loop();
 
 private:
-    OnHalEvent mOnHalEvent;
-    std::thread mThread;
-    mutable std::mutex mLock;
-    std::condition_variable mCond;
     GeneratorCfg mGenCfg;
-    std::atomic_bool mStopRequested{false};
+    int32_t mNumOfIterations;
 };
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
index 8cb9322..7bdc97c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
@@ -29,101 +29,48 @@
 
 namespace impl {
 
-LinearFakeValueGenerator::LinearFakeValueGenerator(const OnHalEvent& onHalEvent)
-    : mOnHalEvent(onHalEvent),
-      mRecurrentTimer(std::bind(&LinearFakeValueGenerator::onTimer, this, std::placeholders::_1)) {}
-
-StatusCode LinearFakeValueGenerator::start(const VehiclePropValue& request) {
+LinearFakeValueGenerator::LinearFakeValueGenerator(const VehiclePropValue& request) {
     const auto& v = request.value;
-    if (v.int32Values.size() < 2) {
-        ALOGE("%s: expected property ID in int32Values", __func__);
-        return StatusCode::INVALID_ARG;
-    }
-    int32_t propId = v.int32Values[1];
-
-    if (!v.int64Values.size()) {
-        ALOGE("%s: interval is not provided in int64Values", __func__);
-        return StatusCode::INVALID_ARG;
-    }
-    auto interval = std::chrono::nanoseconds(v.int64Values[0]);
-
-    if (v.floatValues.size() < 3) {
-        ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
-              v.floatValues.size());
-        return StatusCode::INVALID_ARG;
-    }
-    float initialValue = v.floatValues[0];
-    float dispersion = v.floatValues[1];
-    float increment = v.floatValues[2];
-
-    MuxGuard g(mLock);
-    removeLocked(propId);
-    mGenCfg.insert({propId, GeneratorCfg{
-                                .initialValue = initialValue,
-                                .currentValue = initialValue,
-                                .dispersion = dispersion,
-                                .increment = increment,}});
-
-    mRecurrentTimer.registerRecurrentEvent(interval, propId);
-    return StatusCode::OK;
+    mGenCfg = GeneratorCfg{
+        .propId = v.int32Values[1],
+        .initialValue = v.floatValues[0],
+        .currentValue = v.floatValues[0],
+        .dispersion = v.floatValues[1],
+        .increment = v.floatValues[2],
+        .interval = Nanos(v.int64Values[0]),
+    };
 }
 
-StatusCode LinearFakeValueGenerator::stop(const VehiclePropValue& request) {
-    const auto& v = request.value;
-    if (v.int32Values.size() < 2) {
-        ALOGE("%s: expected property ID in int32Values", __func__);
-        return StatusCode::INVALID_ARG;
+VehiclePropValue LinearFakeValueGenerator::nextEvent() {
+    mGenCfg.currentValue += mGenCfg.increment;
+    if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) {
+        mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion;
     }
-    int32_t propId = v.int32Values[1];
-
-    MuxGuard g(mLock);
-    if (propId == 0) {
-        // Remove all.
-        for (auto&& it : mGenCfg) {
-            removeLocked(it.first);
-        }
-    } else {
-        removeLocked(propId);
+    VehiclePropValue event = {.prop = mGenCfg.propId};
+    auto& value = event.value;
+    switch (getPropType(event.prop)) {
+        case VehiclePropertyType::INT32:
+            value.int32Values.resize(1);
+            value.int32Values[0] = static_cast<int32_t>(mGenCfg.currentValue);
+            break;
+        case VehiclePropertyType::INT64:
+            value.int64Values.resize(1);
+            value.int64Values[0] = static_cast<int64_t>(mGenCfg.currentValue);
+            break;
+        case VehiclePropertyType::FLOAT:
+            value.floatValues.resize(1);
+            value.floatValues[0] = mGenCfg.currentValue;
+            break;
+        default:
+            ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop);
     }
-    return StatusCode::OK;
+    TimePoint eventTime = Clock::now() + mGenCfg.interval;
+    event.timestamp = eventTime.time_since_epoch().count();
+    return event;
 }
 
-void LinearFakeValueGenerator::removeLocked(int propId) {
-    if (mGenCfg.erase(propId)) {
-        mRecurrentTimer.unregisterRecurrentEvent(propId);
-    }
-}
-
-void LinearFakeValueGenerator::onTimer(const std::vector<int32_t>& properties) {
-    MuxGuard g(mLock);
-
-    for (int32_t propId : properties) {
-        auto& cfg = mGenCfg[propId];
-        cfg.currentValue += cfg.increment;
-        if (cfg.currentValue > cfg.initialValue + cfg.dispersion) {
-            cfg.currentValue = cfg.initialValue - cfg.dispersion;
-        }
-        VehiclePropValue event = {.prop = propId};
-        auto& value = event.value;
-        switch (getPropType(event.prop)) {
-            case VehiclePropertyType::INT32:
-                value.int32Values.resize(1);
-                value.int32Values[0] = static_cast<int32_t>(cfg.currentValue);
-                break;
-            case VehiclePropertyType::INT64:
-                value.int64Values.resize(1);
-                value.int64Values[0] = static_cast<int64_t>(cfg.currentValue);
-                break;
-            case VehiclePropertyType::FLOAT:
-                value.floatValues.resize(1);
-                value.floatValues[0] = cfg.currentValue;
-                break;
-            default:
-                ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop);
-                continue;
-        }
-        mOnHalEvent(event);
-    }
+bool LinearFakeValueGenerator::hasNext() {
+    return true;
 }
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
index fe6d097..d3b666d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
@@ -17,8 +17,6 @@
 #ifndef android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_
 #define android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_
 
-#include <vhal_v2_0/RecurrentTimer.h>
-
 #include "FakeValueGenerator.h"
 
 namespace android {
@@ -36,27 +34,24 @@
     // to the client.
 
     struct GeneratorCfg {
-        float initialValue;  //
+        int32_t propId;
+        float initialValue;
         float currentValue;  //  Should be in range (initialValue +/- dispersion).
         float dispersion;    //  Defines minimum and maximum value based on initial value.
         float increment;     //  Value that we will be added to currentValue with each timer tick.
+        Nanos interval;
     };
 
 public:
-    LinearFakeValueGenerator(const OnHalEvent& onHalEvent);
+    LinearFakeValueGenerator(const VehiclePropValue& request);
     ~LinearFakeValueGenerator() = default;
-    StatusCode start(const VehiclePropValue& request) override;
-    StatusCode stop(const VehiclePropValue& request) override;
+
+    VehiclePropValue nextEvent();
+
+    bool hasNext();
 
 private:
-    void removeLocked(int propId);
-    void onTimer(const std::vector<int32_t>& properties);
-
-private:
-    mutable std::mutex mLock;
-    OnHalEvent mOnHalEvent;
-    RecurrentTimer mRecurrentTimer;
-    std::unordered_map<int32_t, GeneratorCfg> mGenCfg;
+    GeneratorCfg mGenCfg;
 };
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index a031ee9..57179df 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -501,7 +501,8 @@
     /**
      * Tire pressure
      *
-     * The min/max range is used to indicate the recommended tire pressure.
+     * min/max value indicates tire pressure sensor range.  Each tire will have a separate min/max
+     * value denoted by its areaConfig.areaId.
      *
      * @change_mode VehiclePropertyChangeMode:CONTINUOUS
      * @access VehiclePropertyAccess:READ
@@ -510,7 +511,7 @@
     TIRE_PRESSURE = (
         0x0309
         | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:MIXED
+        | VehiclePropertyType:FLOAT
         | VehicleArea:WHEEL),
 
     /**
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
index a7f4031..9911038 100644
--- a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
+++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
@@ -19,6 +19,7 @@
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
 #include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
 #include <hidl/HidlSupport.h>
@@ -28,6 +29,7 @@
 #include <future>
 #include <utility>
 
+using android::base::GetUintProperty;
 using android::Condition;
 using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
 using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
@@ -44,7 +46,7 @@
 static const uint32_t kTimeout = 3;
 static const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout);
 static const uint32_t kGroupId = 99;
-static const std::string kTmpDir = "/data/system/users/0/fpdata/";
+static std::string kTmpDir = "";
 static const uint32_t kIterations = 1000;
 
 // Wait for a callback to occur (signaled by the given future) up to the
@@ -199,9 +201,25 @@
         FingerprintHidlEnvironment::Instance()->getServiceName<IBiometricsFingerprint>());
     ASSERT_FALSE(mService == nullptr);
 
-    // Create an active group
-    // FP service can only write to /data/system/users/*/fpdata/ due to
-    // SELinux Policy and Linux Dir Permissions
+    /*
+     * Devices shipped from now on will instead store
+     * fingerprint data under /data/vendor_de/<user-id>/fpdata.
+     * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
+     */
+
+    uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+    if (api_level == 0) {
+      api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+    }
+    ASSERT_TRUE(api_level != 0);
+
+    // 27 is the API number for O-MR1
+    if (api_level <= 27) {
+      kTmpDir = "/data/system/users/0/fpdata/";
+    } else {
+      kTmpDir = "/data/vendor_de/0/fpdata/";
+    }
+
     Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
     ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
   }
diff --git a/broadcastradio/2.0/ITunerCallback.hal b/broadcastradio/2.0/ITunerCallback.hal
index b20a0b2..a174c9c 100644
--- a/broadcastradio/2.0/ITunerCallback.hal
+++ b/broadcastradio/2.0/ITunerCallback.hal
@@ -18,7 +18,8 @@
 interface ITunerCallback {
     /**
      * Method called by the HAL when a tuning operation fails asynchronously
-     * following a step(), scan() or tune() command.
+     * following ITunerSession::tune(), ITunerSession::scan() or
+     * ITunerSession::step().
      *
      * This callback is only called when the step(), scan() or tune() command
      * returned OK at first.
diff --git a/broadcastradio/2.0/ITunerSession.hal b/broadcastradio/2.0/ITunerSession.hal
index e891a23..3c27246 100644
--- a/broadcastradio/2.0/ITunerSession.hal
+++ b/broadcastradio/2.0/ITunerSession.hal
@@ -19,7 +19,7 @@
     /**
      * Tune to a specified program.
      *
-     * Automatically cancels pending scan, step or tune.
+     * Automatically cancels pending tune(), scan() or step().
      * If the method returns OK, tuneFailed or currentProgramInfoChanged
      * callback must be called.
      *
@@ -33,9 +33,16 @@
     tune(ProgramSelector program) generates (Result result);
 
     /**
-     * Tune to the next valid program.
+     * Tune (seek) to the next valid program on the "air".
      *
-     * Automatically cancels pending scan, step or tune.
+     * This might more naturally be called "seek" but for legacy reasons, the
+     * entry point remains "scan". This should not be confused with the actual
+     * scan operation (where the radio seeks through programs in a loop until
+     * user chooses to stay on one of them) nor background scan operation (that
+     * a tuner may do in order to locate all available programs.  This function
+     * is meant to advance to the next detected program and stay there.
+     *
+     * Automatically cancels pending tune(), scan() or step().
      * If the method returns OK, tuneFailed or currentProgramInfoChanged
      * callback must be called.
      *
@@ -44,20 +51,20 @@
      *  - DAB secondary service.
      *
      * As an implementation detail, the HAL has the option to perform an actual
-     * scan or select the next program from the list retrieved in the
+     * seek or select the next program from the list retrieved in the
      * background, if one is not stale.
      *
      * @param directionUp True to change towards higher numeric values
      *                    (frequency, channel number), false towards lower.
      * @param skipSubChannel Don't tune to subchannels.
-     * @return result OK if the scan has successfully started.
+     * @return result OK if the operation has successfully started.
      */
     scan(bool directionUp, bool skipSubChannel) generates (Result result);
 
     /**
      * Tune to the adjacent channel, which may not be occupied by any program.
      *
-     * Automatically cancels pending scan, step or tune.
+     * Automatically cancels pending tune(), scan() or step().
      * If the method returns OK, tuneFailed or currentProgramInfoChanged
      * callback must be called.
      *
@@ -70,7 +77,7 @@
     step(bool directionUp) generates (Result result);
 
     /**
-     * Cancel a scan, step or tune operation.
+     * Cancel a pending tune(), scan() or step().
      *
      * If there is no such operation running, the call must be ignored.
      */
diff --git a/broadcastradio/2.0/default/TunerSession.cpp b/broadcastradio/2.0/default/TunerSession.cpp
index 56a3508..da97562 100644
--- a/broadcastradio/2.0/default/TunerSession.cpp
+++ b/broadcastradio/2.0/default/TunerSession.cpp
@@ -42,7 +42,7 @@
 
 namespace delay {
 
-static constexpr auto scan = 200ms;
+static constexpr auto seek = 200ms;
 static constexpr auto step = 100ms;
 static constexpr auto tune = 150ms;
 static constexpr auto list = 1s;
@@ -131,11 +131,11 @@
     if (list.empty()) {
         mIsTuneCompleted = false;
         auto task = [this, directionUp]() {
-            ALOGI("Performing failed scan up=%d", directionUp);
+            ALOGI("Performing failed seek up=%d", directionUp);
 
             mCallback->onTuneFailed(Result::TIMEOUT, {});
         };
-        mThread.schedule(task, delay::scan);
+        mThread.schedule(task, delay::seek);
 
         return Result::OK;
     }
@@ -162,12 +162,12 @@
 
     mIsTuneCompleted = false;
     auto task = [this, tuneTo, directionUp]() {
-        ALOGI("Performing scan up=%d", directionUp);
+        ALOGI("Performing seek up=%d", directionUp);
 
         lock_guard<mutex> lk(mMut);
         tuneInternalLocked(tuneTo);
     };
-    mThread.schedule(task, delay::scan);
+    mThread.schedule(task, delay::seek);
 
     return Result::OK;
 }
diff --git a/broadcastradio/2.0/default/VirtualProgram.h b/broadcastradio/2.0/default/VirtualProgram.h
index e1c4f75..6502616 100644
--- a/broadcastradio/2.0/default/VirtualProgram.h
+++ b/broadcastradio/2.0/default/VirtualProgram.h
@@ -40,8 +40,8 @@
     operator ProgramInfo() const;
 
     /**
-     * Defines order on how virtual programs appear on the "air" with
-     * ITunerSession::scan operation.
+     * Defines order in which virtual programs appear on the "air" with
+     * ITunerSession::scan().
      *
      * It's for default implementation purposes, may not be complete or correct.
      */
diff --git a/broadcastradio/2.0/types.hal b/broadcastradio/2.0/types.hal
index 1ce61df..987572a 100644
--- a/broadcastradio/2.0/types.hal
+++ b/broadcastradio/2.0/types.hal
@@ -184,18 +184,20 @@
  * lowerBound + channelNumber * spacing, up to upperBound.
  */
 struct AmFmBandRange {
-    /** The frequency of the first channel within the range. */
+    /** The frequency (in kHz) of the first channel within the range. */
     uint32_t lowerBound;
 
-    /** The frequency of the last channel within the range. */
+    /** The frequency (in kHz) of the last channel within the range. */
     uint32_t upperBound;
 
-    /** Channel grid resolution, how far apart are the channels. */
+    /** Channel grid resolution (in kHz), how far apart are the channels. */
     uint32_t spacing;
 
     /**
-     * Spacing used when scanning for channels. It's a multiply of spacing and
-     * allows to skip some channels when scanning to make it faster.
+     * Channel spacing (in kHz) used to speed up seeking to the next station
+     * via the ITunerSession::scan() operation.
+     *
+     * It must be a multiple of channel grid resolution.
      *
      * Tuner may first quickly check every n-th channel and if it detects echo
      * from a station, it fine-tunes to find the exact frequency.
@@ -415,9 +417,10 @@
     TRAFFIC_ANNOUNCEMENT = 1 << 3,
 
     /**
-     * Tuned to a program (not playing a static).
+     * Tuned to a program (not playing static).
      *
-     * It's the same condition that would stop scan() operation.
+     * It's the same condition that would stop a seek operation
+     * (ie: ITunerSession::scan()).
      *
      * By definition, this flag must be set for all items on the program list.
      */
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 62b0037..3d7039d 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -308,7 +308,7 @@
  *  - there is at least one AM/FM band configured;
  *  - FM Deemphasis and RDS are correctly configured for FM-capable radio;
  *  - all channel grids (frequency ranges and spacings) are valid;
- *  - scan spacing is a multiply of manual spacing value.
+ *  - seek spacing is a multiple of the manual spacing value.
  */
 TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfig) {
     AmFmRegionConfig config;
@@ -341,7 +341,7 @@
  *  - there is at least one AM/FM range supported;
  *  - there is at least one de-emphasis filter mode supported for FM-capable radio;
  *  - all channel grids (frequency ranges and spacings) are valid;
- *  - scan spacing is not set.
+ *  - seek spacing is not set.
  */
 TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) {
     AmFmRegionConfig config;
@@ -501,14 +501,14 @@
 }
 
 /**
- * Test scanning to next/prev station.
+ * Test seeking to next/prev station via ITunerSession::scan().
  *
  * Verifies that:
  *  - the method succeeds;
  *  - the program info is changed within timeout::tune;
  *  - works both directions and with or without skipping sub-channel.
  */
-TEST_F(BroadcastRadioHalTest, Scan) {
+TEST_F(BroadcastRadioHalTest, Seek) {
     ASSERT_TRUE(openSession());
 
     // TODO(b/69958777): see FmTune workaround
@@ -564,8 +564,8 @@
     ASSERT_TRUE(openSession());
 
     for (int i = 0; i < 10; i++) {
-        auto scanResult = mSession->scan(true /* up */, true /* skip subchannel */);
-        ASSERT_EQ(Result::OK, scanResult);
+        auto result = mSession->scan(true /* up */, true /* skip subchannel */);
+        ASSERT_EQ(Result::OK, result);
 
         auto cancelResult = mSession->cancel();
         ASSERT_TRUE(cancelResult.isOk());
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index f33da13..69f8535 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -18,6 +18,7 @@
 #include <android/log.h>
 
 #include <set>
+#include <cutils/properties.h>
 #include <utils/Trace.h>
 #include <hardware/gralloc.h>
 #include <hardware/gralloc1.h>
@@ -31,9 +32,9 @@
 namespace implementation {
 
 // Size of request metadata fast message queue. Change to 0 to always use hwbinder buffer.
-static constexpr size_t CAMERA_REQUEST_METADATA_QUEUE_SIZE = 1 << 20 /* 1MB */;
+static constexpr int32_t CAMERA_REQUEST_METADATA_QUEUE_SIZE = 1 << 20 /* 1MB */;
 // Size of result metadata fast message queue. Change to 0 to always use hwbinder buffer.
-static constexpr size_t CAMERA_RESULT_METADATA_QUEUE_SIZE  = 1 << 20 /* 1MB */;
+static constexpr int32_t CAMERA_RESULT_METADATA_QUEUE_SIZE  = 1 << 20 /* 1MB */;
 
 // Metadata sent by HAL will be replaced by a compact copy
 // if their (total size >= compact size + METADATA_SHRINK_ABS_THRESHOLD &&
@@ -95,14 +96,30 @@
         return true;
     }
 
+    int32_t reqFMQSize = property_get_int32("ro.camera.req.fmq.size", /*default*/-1);
+    if (reqFMQSize < 0) {
+        reqFMQSize = CAMERA_REQUEST_METADATA_QUEUE_SIZE;
+    } else {
+        ALOGV("%s: request FMQ size overridden to %d", __FUNCTION__, reqFMQSize);
+    }
+
     mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
-            CAMERA_REQUEST_METADATA_QUEUE_SIZE, false /* non blocking */);
+            static_cast<size_t>(reqFMQSize),
+            false /* non blocking */);
     if (!mRequestMetadataQueue->isValid()) {
         ALOGE("%s: invalid request fmq", __FUNCTION__);
         return true;
     }
+
+    int32_t resFMQSize = property_get_int32("ro.camera.res.fmq.size", /*default*/-1);
+    if (resFMQSize < 0) {
+        resFMQSize = CAMERA_RESULT_METADATA_QUEUE_SIZE;
+    } else {
+        ALOGV("%s: result FMQ size overridden to %d", __FUNCTION__, resFMQSize);
+    }
     mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
-            CAMERA_RESULT_METADATA_QUEUE_SIZE, false /* non blocking */);
+            static_cast<size_t>(resFMQSize),
+            false /* non blocking */);
     if (!mResultMetadataQueue->isValid()) {
         ALOGE("%s: invalid result fmq", __FUNCTION__);
         return true;
@@ -1374,6 +1391,8 @@
         std::vector<const camera_metadata_t*>* physCamMdArray,
         bool handlePhysCam) {
     *dst = *src;
+    // Reserve maximum number of entries to avoid metadata re-allocation.
+    mds->reserve(1 + (handlePhysCam ? src->num_physcam_metadata : 0));
     if (sShouldShrink(src->result)) {
         mds->emplace_back(sCreateCompactCopy(src->result));
         dst->result = mds->back().getAndLock();
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index ff7c0ee..95c7167 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -3480,11 +3480,10 @@
         ret = session->close();
         ASSERT_TRUE(ret.isOk());
 
+        // Leave only 2 physical devices in the id set.
         auto it = physicalIds.begin();
-        string physicalDeviceId = *it;
-        // Leave only the first physical device in the id set and insert the logical device.
+        string physicalDeviceId = *it; it++;
         physicalIds.erase(++it, physicalIds.end());
-        physicalIds.emplace(deviceId);
         ASSERT_EQ(physicalIds.size(), 2u);
 
         V3_4::HalStreamConfiguration halStreamConfig;
diff --git a/configstore/README.md b/configstore/README.md
new file mode 100644
index 0000000..3e8a24e
--- /dev/null
+++ b/configstore/README.md
@@ -0,0 +1 @@
+Configstore is specifically the configuration for surface flinger. Other configurations go in other packages.
diff --git a/confirmationui/1.0/default/service.cpp b/confirmationui/1.0/default/service.cpp
index 58ec66a..39f3f62 100644
--- a/confirmationui/1.0/default/service.cpp
+++ b/confirmationui/1.0/default/service.cpp
@@ -27,6 +27,7 @@
 using android::hardware::confirmationui::V1_0::implementation::ConfirmationUI;
 
 int main() {
+    ::android::hardware::configureRpcThreadpool(1, true /*willJoinThreadpool*/);
     auto confirmationui = new ConfirmationUI();
     auto status = confirmationui->registerAsService();
     if (status != android::OK) {
diff --git a/current.txt b/current.txt
index 15b096b..cc15322 100644
--- a/current.txt
+++ b/current.txt
@@ -251,8 +251,6 @@
 
 # ABI preserving changes to HALs during Android P
 9e7a0b650d0e461ece2cfec0e1072abf8676f592b41a7fb48f01e88fc3c8f780 android.hardware.broadcastradio@1.0::types
-eaeb3e4f3237430a7fdc206bffdf844713f5682990b2d49ea24392e15b5d343f android.hardware.broadcastradio@2.0::ITunerCallback
-2804120c1f8522ad15feb7695fe5eece527d399b406c671ea99618194118c316 android.hardware.broadcastradio@2.0::types
 cf72ff5a52bfa4d08e9e1000cf3ab5952a2d280c7f13cdad5ab7905c08050766 android.hardware.camera.metadata@3.2::types
 3902efc42097cba55f0655aa389e052ea70164e99ced1a6d1ef53dafc13f7650 android.hardware.camera.provider@2.4::ICameraProvider
 6fa9804a17a8bb7923a56bd10493a5483c20007e4c9026fd04287bee7c945a8c android.hardware.gnss@1.0::IGnssCallback
@@ -267,7 +265,7 @@
 ad8a28ca3a5549fb9bc24cf5f80ac8f660cc27be885210d76266780aa52ddb8d android.hardware.keymaster@3.0::types
 5804ca86611d72e5481f022b3a0c1b334217f2e4988dad25730c42af2d1f4d1c android.hardware.neuralnetworks@1.0::IDevice
 12e8dca4ab7d8aadd0ef8f1b438021938e2396139e85db2ed65783b08800aa52 android.hardware.neuralnetworks@1.0::IExecutionCallback
-18e6885e184fe48401c2c53f1d1b8bfb07240f40c81ae6b9d2e336fca6efdbb7 android.hardware.neuralnetworks@1.0::types
+86b77e06da756a76aa3685be88765852dd982a86d8c90b8b4fc1130ed4184c8f android.hardware.neuralnetworks@1.0::types
 d4840db8efabdf1e4b344fc981cd36e5fe81a39aff6e199f6d06c1c8da413efd android.hardware.radio@1.0::types
 f96cbc59dfe16c8d0c2a7e06db24d8738a6328b6e90f7b8e1640ea2b4600debd android.hardware.radio@1.1::ISap
 2d86929794795e5c70f4fdb5073485fd05835c9c6f496116687c3d9f32e6df3e android.hardware.radio@1.2::ISap
@@ -302,25 +300,15 @@
 fe28829dab10d171783b79ac9cc45412739f8ff275e90228d7c6370ef189b859 android.hardware.audio.effect@4.0::IVisualizerEffect
 21c8a702579356480236c6851b5b2c16b9bd369ce12bdd6ffdc4626a89f34f73  android.hardware.audio.effect@4.0::types
 42a06dc288f61b0690580f3d37b30b663c31d74d50bb58d0772386b550d5faab android.hardware.authsecret@1.0::IAuthSecret
-a0f93c768c353cecee6237fe479bce47404eb10b629fafe07e32a054fd67f2af android.hardware.automotive.audiocontrol@1.0::IAudioControl
-ca515ff4b63c80cf5ad7b3395c997c57d6c56157361f6c367d1c96f23cc4860a android.hardware.automotive.audiocontrol@1.0::types
-f2904a4c108ad1b93eb2fa4e43b82bd01ce1ff26156316e49d1d9fc80dfecaad android.hardware.automotive.evs@1.0::IEvsCamera
-94cba6ad04c83aa840de2ed52b74ba2126a26dd960225e61ac36703315279a80 android.hardware.automotive.evs@1.0::IEvsCameraStream
-5ea36fb043d9e3b413219de3dfd7b046b48af4fda39f167f3528652e986cb76d android.hardware.automotive.evs@1.0::IEvsDisplay
-14ef8e993a4a7c899b19bb5e39b5b0cafd28312ea2b127e35b3be8f08e23fe8e android.hardware.automotive.evs@1.0::IEvsEnumerator
-3b17c1fdfc389e0abe626c37054954b07201127d890c2bc05d47613ec1f4de4f android.hardware.automotive.evs@1.0::types
-b3caf524c46a47d67e6453a34419e1881942d059e146cda740502670e9a752c3 android.hardware.automotive.vehicle@2.0::IVehicle
-7ce8728b27600e840cacf0a832f6942819fe535f9d3797ae052d5eef5065921c android.hardware.automotive.vehicle@2.0::IVehicleCallback
-3562503f550f70eec7a688343a600fb92b74efb807a31452b70195dfab328b22 android.hardware.automotive.vehicle@2.0::types
 32cc50cc2a7658ec613c0c2dd2accbf6a05113b749852879e818b8b7b438db19 android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioHost
 ff4be64d7992f8bec97dff37f35450e79b3430c61f85f54322ce45bef229dc3b android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload
 27f22d2e873e6201f9620cf4d8e2facb25bd0dd30a2b911e441b4600d560fa62 android.hardware.bluetooth.a2dp@1.0::types
 3d8ed67d807e9f15d0708390a416bee00920f6a22196c104cc9e443c8d217df8 android.hardware.broadcastradio@2.0::IAnnouncementListener
 44017c42e6f4d8cb30f07eb1da04540a98736a336ac28c7e0ed2e69e1589f8d1 android.hardware.broadcastradio@2.0::IBroadcastRadio
 e5f4960290b4f3089163dd43251e1a032c81e9bdb796e75a87fc7c5810c262b3 android.hardware.broadcastradio@2.0::ICloseHandle
-7357516e8f4585e211b9b6f271af6fb82d6e9cc208df01851e63118404621e6d android.hardware.broadcastradio@2.0::ITunerCallback
-eacf4e7491fc52c4db90898faddf25ec7bc72501b07ae8737434c47cb845128c android.hardware.broadcastradio@2.0::ITunerSession
-34fe4601072aa5051eb8e41d776a9f6d43f716687de3f5c0031a12e7912ff3d6 android.hardware.broadcastradio@2.0::types
+af24b87ca8b8f02fcde205e47db6a9609fc7e9d77d73e694ec8f9c508ca19575 android.hardware.broadcastradio@2.0::ITunerCallback
+d70464c517a4a1b5167730843775a97f455102919e945b04f717b9da390c0f39 android.hardware.broadcastradio@2.0::ITunerSession
+2afa59ebf8145e7fbc090cf49605c27280c07d4178d47cd7f9d82b3b95a47af0 android.hardware.broadcastradio@2.0::types
 4fb0725c36ed4f77a42b42e3f18d8b5f7919cb62b90098b23143a555aa7dd96d android.hardware.camera.device@3.4::ICameraDeviceCallback
 812fa66aa10ba0cba27cfddc2fd7f0ee27a8ab65a1f15aa79fdad97d403e6a14 android.hardware.camera.device@3.4::ICameraDeviceSession
 cc288f1f78d1e643eb3d3dbc16e1401d44033d8e6856761f5156814a29986ec7 android.hardware.camera.device@3.4::types
@@ -342,13 +330,13 @@
 0b96e0254e2168cfecb30c1ed5fb42681652cc00faa68c6e07568fafe64d1d50 android.hardware.graphics.common@1.1::types
 7d2cef99c838fb58038de8bbfd3cdb76ff4797241987077721715297f8d45e34 android.hardware.graphics.common@1.1::types # b/78135149
 d9b40a5b09962a5a0780b10fe33a4e607e69e2e088fc83de88a584115b7cb1c0 android.hardware.graphics.composer@2.2::IComposer
-e7717f2ff2f6db43b24370ff08e14cd353da3004b32b17740e4a7ed4894b7e45 android.hardware.graphics.composer@2.2::IComposerClient
+a2f183f7fcc79aabedaef11095ab223aac0ed5ef984d850893872515e7f560c7 android.hardware.graphics.composer@2.2::IComposerClient
 dd83be076b6b3f10ed62ab34d8c8b95f2415961fb785200eb842e7bfb2b0ee92 android.hardware.graphics.mapper@2.1::IMapper
 675682dd3007805c985eaaec91612abc88f4c25b3431fb84070b7584a1a741fb android.hardware.health@2.0::IHealth
 434c4c32c00b0e54bb05e40c79503208b40f786a318029a2a4f66e34f10f2a76 android.hardware.health@2.0::IHealthInfoCallback
 c9e498f1ade5e26f00d290b4763a9671ec6720f915e7d592844b62e8cb1f9b5c android.hardware.health@2.0::types
-5c8e06f9945276d1a9e8f7e37cf0ea8894bdb906fa80809cb06c36abb39afc4f android.hardware.keymaster@4.0::IKeymasterDevice
-6695eb5744108035506004dd136068b1aaebe809cf9d4a69c2fe33b73058bb85 android.hardware.keymaster@4.0::types
+201f9723353fdbd40bf3705537fb7e015e4c399879425e68688fe0f43606ea4d android.hardware.keymaster@4.0::IKeymasterDevice
+1b7d2090c0a28b229d37c4b96160796b1f0d703950ac6ccc163fccd280830503 android.hardware.keymaster@4.0::types
 6d5c646a83538f0f9d8438c259932509f4353410c6c76e56db0d6ca98b69c3bb android.hardware.media.bufferpool@1.0::IAccessor
 b8c7ed58aa8740361e63d0ce9e7c94227572a629f356958840b34809d2393a7c android.hardware.media.bufferpool@1.0::IClientManager
 4a2c0dc82780e6c90731725a103feab8ab6ecf85a64e049b9cbd2b2c61620fe1 android.hardware.media.bufferpool@1.0::IConnection
diff --git a/gnss/1.1/default/Gnss.cpp b/gnss/1.1/default/Gnss.cpp
index bbc4940..bbf1cd3 100644
--- a/gnss/1.1/default/Gnss.cpp
+++ b/gnss/1.1/default/Gnss.cpp
@@ -227,7 +227,9 @@
         getSvInfo(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
         getSvInfo(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
         getSvInfo(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
-        getSvInfo(30, GnssConstellationType::GPS, 20.5, 11.5, 116.0),
+        getSvInfo(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
+        getSvInfo(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
+        getSvInfo(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
         getSvInfo(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
 
     GnssSvStatus svStatus = {.numSvs = sizeof(mockGnssSvInfoList) / sizeof(GnssSvInfo)};
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 8928a5a..46d61e5 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -191,7 +191,7 @@
 void GnssHalTest::StartAndCheckLocations(int count) {
     const int kMinIntervalMsec = 500;
     const int kLocationTimeoutSubsequentSec = 2;
-    const bool kLowPowerMode = true;
+    const bool kLowPowerMode = false;
 
     SetPositionMode(kMinIntervalMsec, kLowPowerMode);
 
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 8f4691e..cce46f1 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -84,15 +84,15 @@
 }
 
 /*
- * FindStrongFrequentSource:
+ * FindStrongFrequentNonGpsSource:
  *
- * Search through a GnssSvStatus list for the strongest satellite observed enough times
+ * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
  *
  * returns the strongest source,
  *         or a source with constellation == UNKNOWN if none are found sufficient times
  */
 
-IGnssConfiguration::BlacklistedSource FindStrongFrequentSource(
+IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
     const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
     struct ComparableBlacklistedSource {
         IGnssConfiguration::BlacklistedSource id;
@@ -113,7 +113,8 @@
     for (const auto& gnss_sv_status : list_gnss_sv_status) {
         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
-            if (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) {
+            if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.constellation != GnssConstellationType::GPS)) {
                 ComparableBlacklistedSource source;
                 source.id.svid = gnss_sv.svid;
                 source.id.constellation = gnss_sv.constellation;
@@ -187,8 +188,12 @@
      */
 
     IGnssConfiguration::BlacklistedSource source_to_blacklist =
-        FindStrongFrequentSource(list_gnss_sv_status_, kLocationsToAwait - 1);
-    EXPECT_NE(source_to_blacklist.constellation, GnssConstellationType::UNKNOWN);
+        FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1);
+
+    if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
+        // Cannot find a non-GPS satellite. Let the test pass.
+        return;
+    }
 
     // Stop locations, blacklist the common SV
     StopAndClearLocations();
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
index d0167d9..366d641 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -858,18 +858,20 @@
         return Error::Unsupported;
     }
 
-    uint32_t hwc1Config = 0;
-    auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config);
-    if (error != Error::None) {
-        return error;
-    }
+    if (mDevice.mHwc1MinorVersion >= 4) {
+        uint32_t hwc1Config = 0;
+        auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config);
+        if (error != Error::None) {
+            return error;
+        }
 
-    ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config);
-    int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
-            mHwc1Id, hwc1Config);
-    if (intError != 0) {
-        ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError);
-        return Error::Unsupported;
+        ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config);
+        int intError =
+            mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, hwc1Config);
+        if (intError != 0) {
+            ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError);
+            return Error::Unsupported;
+        }
     }
 
     mActiveColorMode = mode;
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 8b8b530..72f3f1b 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -292,9 +292,16 @@
  * Test that IComposerClient::setColorMode succeeds for all color modes.
  */
 TEST_F(GraphicsComposerHidlTest, SetColorMode) {
+    std::unordered_set<ColorMode> validModes;
+    for (auto mode : hidl_enum_range<ColorMode>()) {
+        validModes.insert(mode);
+    }
+
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
     for (auto mode : modes) {
-        mComposerClient->setColorMode(mPrimaryDisplay, mode);
+        if (validModes.count(mode)) {
+            mComposerClient->setColorMode(mPrimaryDisplay, mode);
+        }
     }
 }
 
diff --git a/graphics/composer/2.2/IComposerClient.hal b/graphics/composer/2.2/IComposerClient.hal
index 2f0a3cc..d4a87e6 100644
--- a/graphics/composer/2.2/IComposerClient.hal
+++ b/graphics/composer/2.2/IComposerClient.hal
@@ -355,7 +355,8 @@
      * Returns the render intents supported by the specified display and color
      * mode.
      *
-     * RenderIntent::COLORIMETRIC is always supported.
+     * For SDR color modes, RenderIntent::COLORIMETRIC must be supported. For
+     * HDR color modes, RenderIntent::TONE_MAP_COLORIMETRIC must be supported.
      *
      * @param display is the display to query.
      * @param mode is the color mode to query.
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 2f1c66e..e3b7f55 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -345,9 +345,22 @@
     for (auto mode : modes) {
         std::vector<RenderIntent> intents =
             mComposerClient->getRenderIntents(mPrimaryDisplay, mode);
-        auto colorimetricIntent =
-            std::find(intents.cbegin(), intents.cend(), RenderIntent::COLORIMETRIC);
-        EXPECT_NE(intents.cend(), colorimetricIntent);
+
+        bool isHdr;
+        switch (mode) {
+            case ColorMode::BT2100_PQ:
+            case ColorMode::BT2100_HLG:
+                isHdr = true;
+                break;
+            default:
+                isHdr = false;
+                break;
+        }
+        RenderIntent requiredIntent =
+            isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;
+
+        auto iter = std::find(intents.cbegin(), intents.cend(), requiredIntent);
+        EXPECT_NE(intents.cend(), iter);
     }
 }
 
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index 3a181a9..77fd6f7 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -294,7 +294,7 @@
 }
 
 bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain) {
-    for (size_t i = 0; i < chain.size() - 1; ++i) {
+    for (size_t i = 0; i < chain.size(); ++i) {
         X509_Ptr key_cert(parse_cert_blob(chain[i]));
         X509_Ptr signing_cert;
         if (i < chain.size() - 1) {
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index 6c09ef3..74d13d8 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -217,8 +217,8 @@
      * must be a TEE Keymaster as well.  The HMAC key used to MAC and verify authentication tokens
      * (HardwareAuthToken, VerificationToken and ConfirmationToken all use this HMAC key) must be
      * shared between TEE and StrongBox so they can each validate tokens produced by the other.
-     * This method is the first step in the process for for agreeing on a shared key.  It is called
-     * by Android during startup.  The system calls it on each of the HAL instances and collects the
+     * This method is the first step in the process for agreeing on a shared key.  It is called by
+     * Android during startup.  The system calls it on each of the HAL instances and collects the
      * results in preparation for the second step.
      *
      * @return error ErrorCode::OK on success, ErrorCode::UNIMPLEMENTED if HMAC agreement is not
@@ -324,7 +324,7 @@
      *             sharingCheck = HMAC(H, "Keymaster HMAC Verification")
      *
      *         The string is UTF-8 encoded, 27 bytes in length.  If the returned values of all
-     *         IKeymasterDevice instances don't match, Keystore will assume that HMAC agreement
+     *         IKeymasterDevice instances don't match, clients must assume that HMAC agreement
      *         failed.
      */
     computeSharedHmac(vec<HmacSharingParameters> params)
@@ -718,16 +718,19 @@
      * AuthorizationList ::= SEQUENCE {
      *     purpose                    [1] EXPLICIT SET OF INTEGER OPTIONAL,
      *     algorithm                  [2] EXPLICIT INTEGER OPTIONAL,
-     *     keySize                    [3] EXPLICIT INTEGER OPTIONAL.
+     *     keySize                    [3] EXPLICIT INTEGER OPTIONAL,
      *     blockMode                  [4] EXPLICIT SET OF INTEGER OPTIONAL,
      *     digest                     [5] EXPLICIT SET OF INTEGER OPTIONAL,
      *     padding                    [6] EXPLICIT SET OF INTEGER OPTIONAL,
+     *     callerNonce                [7] EXPLICIT NULL OPTIONAL,
+     *     minMacLength               [8] EXPLICIT INTEGER OPTIONAL,
      *     ecCurve                    [10] EXPLICIT INTEGER OPTIONAL,
      *     rsaPublicExponent          [200] EXPLICIT INTEGER OPTIONAL,
      *     rollbackResistance         [303] EXPLICIT NULL OPTIONAL,
-     *     activeDateTime             [400] EXPLICIT INTEGER OPTIONAL
-     *     originationExpireDateTime  [401] EXPLICIT INTEGER OPTIONAL
-     *     usageExpireDateTime        [402] EXPLICIT INTEGER OPTIONAL
+     *     activeDateTime             [400] EXPLICIT INTEGER OPTIONAL,
+     *     originationExpireDateTime  [401] EXPLICIT INTEGER OPTIONAL,
+     *     usageExpireDateTime        [402] EXPLICIT INTEGER OPTIONAL,
+     *     userSecureId               [502] EXPLICIT INTEGER OPTIONAL,
      *     noAuthRequired             [503] EXPLICIT NULL OPTIONAL,
      *     userAuthType               [504] EXPLICIT INTEGER OPTIONAL,
      *     authTimeout                [505] EXPLICIT INTEGER OPTIONAL,
@@ -735,15 +738,11 @@
      *     trustedUserPresenceReq     [507] EXPLICIT NULL OPTIONAL,
      *     trustedConfirmationReq     [508] EXPLICIT NULL OPTIONAL,
      *     unlockedDeviceReq          [509] EXPLICIT NULL OPTIONAL,
-     *     allApplications            [600] EXPLICIT NULL OPTIONAL,
-     *     applicationId              [601] EXPLICIT OCTET_STRING OPTIONAL,
      *     creationDateTime           [701] EXPLICIT INTEGER OPTIONAL,
      *     origin                     [702] EXPLICIT INTEGER OPTIONAL,
-     *     rollbackResistant          [703] EXPLICIT NULL OPTIONAL,
      *     rootOfTrust                [704] EXPLICIT RootOfTrust OPTIONAL,
      *     osVersion                  [705] EXPLICIT INTEGER OPTIONAL,
      *     osPatchLevel               [706] EXPLICIT INTEGER OPTIONAL,
-     *     attestationChallenge       [708] EXPLICIT OCTET_STRING OPTIONAL,
      *     attestationApplicationId   [709] EXPLICIT OCTET_STRING OPTIONAL,
      *     attestationIdBrand         [710] EXPLICIT OCTET_STRING OPTIONAL,
      *     attestationIdDevice        [711] EXPLICIT OCTET_STRING OPTIONAL,
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
index 85f181a..94dfec5 100644
--- a/keymaster/4.0/types.hal
+++ b/keymaster/4.0/types.hal
@@ -460,6 +460,8 @@
      * called on one key with TRUSTED_USER_PRESENCE_REQUIRED, and another begin() comes in for that
      * key or another with TRUSTED_USER_PRESENCE_REQUIRED, Keymaster must return
      * ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED.
+     *
+     * Must be hardware-enforced.
      */
     TRUSTED_USER_PRESENCE_REQUIRED = TagType:BOOL | 507,
 
@@ -470,11 +472,17 @@
      *
      * If an attempt to use a key with this tag does not have a cryptographically valid
      * CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not
-     * match the data described in the token, keymaster must return NO_USER_CONFIRMATION. */
+     * match the data described in the token, keymaster must return NO_USER_CONFIRMATION.
+     *
+     * Must be hardware-enforced.
+     */
     TRUSTED_CONFIRMATION_REQUIRED = TagType:BOOL | 508,
 
     /**
+     * Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is
+     * unlocked.
      *
+     * Must be software-enforced.
      */
     UNLOCKED_DEVICE_REQUIRED = TagType:BOOL | 509,
 
@@ -490,7 +498,7 @@
      * access to the tag content to decrypt the key without brute-forcing the tag content, which
      * applications can prevent by specifying sufficiently high-entropy content.
      *
-     * Must be hardware-enforced.
+     * Must never appear in KeyCharacteristics.
      */
     APPLICATION_ID = TagType:BYTES | 601,
 
@@ -511,7 +519,7 @@
      * access to the tag content to decrypt the key without brute-forcing the tag content, which
      * applications can prevent by specifying sufficiently high-entropy content.
      *
-     * Must be hardware-enforced.
+     * Must never appear in KeyCharacteristics.
      */
     APPLICATION_DATA = TagType:BYTES | 700,
 
@@ -557,11 +565,12 @@
      * key generated on Android version 4.0.3, the value would be 040003.
      *
      * The IKeymasterDevice HAL must read the current OS version from the system property
-     * ro.build.id and deliver it to the secure environment when the HAL is first loaded (mechanism
-     * is implementation-defined).  The secure environment must not accept another version until
-     * after the next boot.  If the content of ro.build.id has additional version information after
-     * the sub-minor version number, it must not be included in Tag::OS_VERSION.  If the content is
-     * non-numeric, the secure environment must use 0 as the system version.
+     * ro.build.version.release and deliver it to the secure environment when the HAL is first
+     * loaded (mechanism is implementation-defined).  The secure environment must not accept another
+     * version until after the next boot.  If the content of ro.build.version.release has additional
+     * version information after the sub-minor version number, it must not be included in
+     * Tag::OS_VERSION.  If the content is non-numeric, the secure environment must use 0 as the
+     * system version.
      *
      * Must be hardware-enforced.
      */
@@ -659,8 +668,8 @@
 
     /**
      * Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in
-     * Android, to attestKey().  This field is set only when requesting attestation of the device's
-     * identifiers.
+     * Android, to attestKey().  This field must be set only when requesting attestation of the
+     * device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
      * called and the device can no longer attest its IDs), any key attestation request that
@@ -672,8 +681,8 @@
 
     /**
      * Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in
-     * Android, to attestKey().  This field is set only when requesting attestation of the device's
-     * identifiers.
+     * Android, to attestKey().  This field must be set only when requesting attestation of the
+     * device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
      * called and the device can no longer attest its IDs), any key attestation request that
@@ -685,7 +694,7 @@
 
     /**
      * Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT
-     * in Android, to attestKey().  This field is set only when requesting attestation of the
+     * in Android, to attestKey().  This field must be set only when requesting attestation of the
      * device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
@@ -697,7 +706,7 @@
     ATTESTATION_ID_PRODUCT = TagType:BYTES | 712,
 
     /**
-     * Tag::ATTESTATION_ID_SERIAL the device's serial number.  This field is set only when
+     * Tag::ATTESTATION_ID_SERIAL the device's serial number.  This field must be set only when
      * requesting attestation of the device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
@@ -710,7 +719,7 @@
 
     /**
      * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attestKey().
-     * This field is set only when requesting attestation of the device's identifiers.
+     * This field must be set only when requesting attestation of the device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
      * called and the device can no longer attest its IDs), any key attestation request that
@@ -723,7 +732,7 @@
 
     /**
      * Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attestKey().
-     * This field will only be set when requesting attestation of the device's identifiers.
+     * This field must be set only when requesting attestation of the device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
      * called and the device can no longer attest its IDs), any key attestation request that
@@ -736,7 +745,7 @@
 
     /**
      * Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by
-     * Build.MANUFACTURER in Android, to attstKey().  This field is set only when requesting
+     * Build.MANUFACTURER in Android, to attstKey().  This field must be set only when requesting
      * attestation of the device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
@@ -749,8 +758,8 @@
 
     /**
      * Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in
-     * Android, to attestKey().  This field is set only when requesting attestation of the device's
-     * identifiers.
+     * Android, to attestKey().  This field must be set only when requesting attestation of the
+     * device's identifiers.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
      * called and the device can no longer attest its IDs), any key attestation request that
@@ -815,7 +824,7 @@
      * Tag::NONCE is used to provide or return a nonce or Initialization Vector (IV) for AES-GCM,
      * AES-CBC, AES-CTR, or 3DES-CBC encryption or decryption.  This tag is provided to begin during
      * encryption and decryption operations.  It is only provided to begin if the key has
-     * Tag::CALLER_NONCE.  If not provided, an appropriate nonce or IV will be randomly generated by
+     * Tag::CALLER_NONCE.  If not provided, an appropriate nonce or IV must be randomly generated by
      * Keymaster and returned from begin.
      *
      * The value is a blob, an arbitrary-length array of bytes.  Allowed lengths depend on the mode:
diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
index 42f9947..725e290 100644
--- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
+++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
@@ -86,6 +86,11 @@
                                this->omxNode = _nl;
                            })
                         .isOk());
+        if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
+            disableTest = true;
+            std::cout << "[   WARN   ] Test Disabled, component not present\n";
+            return;
+        }
         ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
         ASSERT_NE(omxNode, nullptr);
         ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp
index d5f1f2d..0ebab88 100644
--- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp
+++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp
@@ -86,6 +86,11 @@
                                this->omxNode = _nl;
                            })
                         .isOk());
+        if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
+            disableTest = true;
+            std::cout << "[   WARN   ] Test Disabled, component not present\n";
+            return;
+        }
         ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
         ASSERT_NE(omxNode, nullptr);
         ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
index c37f7ae..4ddc833 100644
--- a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
+++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
@@ -80,6 +80,11 @@
                                this->omxNode = _nl;
                            })
                         .isOk());
+        if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
+            disableTest = true;
+            std::cout << "[   WARN   ] Test Disabled, component not present\n";
+            return;
+        }
         ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
         ASSERT_NE(omxNode, nullptr);
         ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp
index 40e76c9..1db9f75 100644
--- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp
+++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp
@@ -87,6 +87,11 @@
                                this->omxNode = _nl;
                            })
                         .isOk());
+        if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
+            disableTest = true;
+            std::cout << "[   WARN   ] Test Disabled, component not present\n";
+            return;
+        }
         ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
         ASSERT_NE(omxNode, nullptr);
         ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
index 2056d9e..a740a80 100644
--- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
+++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
@@ -100,6 +100,11 @@
                                this->omxNode = _nl;
                            })
                         .isOk());
+        if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
+            disableTest = true;
+            std::cout << "[   WARN   ] Test Disabled, component not present\n";
+            return;
+        }
         ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
         ASSERT_NE(omxNode, nullptr);
         ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index 4efa13a..1ae1726 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -1519,6 +1519,41 @@
 
     /**
      * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * For a tensor operand, dimensions.size() must be at least 1;
+     * however, any of the dimensions may be unspecified.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT or MODEL_OUTPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input or output is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
      */
     vec<uint32_t> dimensions;
 
@@ -1662,10 +1697,19 @@
     /**
      * Updated dimension information.
      *
-     * If dimensions.size() > 0, dimension information was provided along with
-     * the argument. This can be the case for models that accept inputs of
-     * varying size. This can't change the rank, just the value of the
-     * dimensions that were unspecified in the model.
+     * If dimensions.size() > 0, dimension information was provided
+     * along with the argument. This can be the case for models that
+     * accept inputs of varying size. This can't change the rank, just
+     * the value of the dimensions that were unspecified in the
+     * model. If dimensions.size() > 0, then all dimensions must be
+     * specified here; and any dimension that was specified in the
+     * model must have the same value here.
+     *
+     * If the dimensions in the model are not fully specified, then
+     * they must be fully specified here, unless hasNoValue is set to
+     * true. If the dimensions in the model are fully specified, then
+     * either dimensions.size() may be 0, or the dimensions in the
+     * model must be identical to the dimensions here.
      */
     vec<uint32_t> dimensions;
 };
diff --git a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
index dab81e2..3ea3e8d 100644
--- a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
+++ b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
@@ -134,6 +134,7 @@
     EXPECT_LE((unsigned int)2, response.selectResponse.size());
     EXPECT_LE(1, response.channelNumber);
     std::vector<uint8_t> command = DATA_APDU;
+    command[0] |= response.channelNumber;
     std::vector<uint8_t> transmitResponse;
     se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
         transmitResponse.resize(res.size());
@@ -168,7 +169,8 @@
                               }
                           });
     if (statusReturned == SecureElementStatus::SUCCESS) {
-        EXPECT_LE((unsigned int)3, response.size());
+        EXPECT_LE((unsigned int)2, response.size());
+        se_->closeChannel(0);
         return;
     }
     EXPECT_EQ(SecureElementStatus::UNSUPPORTED_OPERATION, statusReturned);
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
index 3bd0557..c4da184 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -111,16 +111,16 @@
 bool removeOldFilesInternal() {
     time_t now = time(0);
     const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
-    DIR* dir_dump = opendir(kTombstoneFolderPath);
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(
+        opendir(kTombstoneFolderPath), closedir);
     if (!dir_dump) {
         LOG(ERROR) << "Failed to open directory: " << strerror(errno);
         return false;
     }
-    unique_fd dir_auto_closer(dirfd(dir_dump));
     struct dirent* dp;
     bool success = true;
     std::list<std::pair<const time_t, std::string>> valid_files;
-    while ((dp = readdir(dir_dump))) {
+    while ((dp = readdir(dir_dump.get()))) {
         if (dp->d_type != DT_REG) {
             continue;
         }
@@ -246,13 +246,13 @@
 size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
     struct dirent* dp;
     size_t n_error = 0;
-    DIR* dir_dump = opendir(input_dir);
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir),
+                                                       closedir);
     if (!dir_dump) {
         LOG(ERROR) << "Failed to open directory: " << strerror(errno);
         return ++n_error;
     }
-    unique_fd dir_auto_closer(dirfd(dir_dump));
-    while ((dp = readdir(dir_dump))) {
+    while ((dp = readdir(dir_dump.get()))) {
         if (dp->d_type != DT_REG) {
             continue;
         }