Merge "Add hwcomposer to the system-background cpuset for hal v2.2" into pi-dev am: f053b3de23
am: db4740805a

Change-Id: Ie87f06f6689921ed1afaaaca168e19f8e5838232
diff --git a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index dab9f7c..9be9b12 100644
--- a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -1100,11 +1100,10 @@
 }
 
 TEST_P(InputStreamTest, getActiveMicrophones) {
-    doc::test("Getting active microphones should always succeed");
+    doc::test("Active microphones of a non started stream may not be retrievable");
     hidl_vec<MicrophoneInfo> microphones;
-    ASSERT_OK(device->getMicrophones(returnIn(res, microphones)));
-    ASSERT_OK(res);
-    ASSERT_TRUE(microphones.size() > 0);
+    ASSERT_OK(stream->getActiveMicrophones(returnIn(res, microphones)));
+    ASSERT_RESULT(okOrNotSupported, res);
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
index 43e5d6e..a9f59fb 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
@@ -106,8 +106,8 @@
     return rc;
 }
 
-IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) {
-    return new DevicesFactory();
+IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name) {
+    return strcmp(name, "default") == 0 ? new DevicesFactory() : nullptr;
 }
 
 }  // namespace implementation
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
index 1882a2c..f27c739 100644
--- a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
@@ -183,8 +183,8 @@
     return Void();
 }
 
-IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* /* name */) {
-    return new EffectsFactory();
+IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name) {
+    return strcmp(name, "default") == 0 ? new EffectsFactory() : nullptr;
 }
 
 }  // namespace implementation
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 eb9d660..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
@@ -70,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,
 
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/biometrics/face/1.0/Android.bp b/biometrics/face/1.0/Android.bp
new file mode 100644
index 0000000..61bf247
--- /dev/null
+++ b/biometrics/face/1.0/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.biometrics.face@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IBiometricsFace.hal",
+        "IBiometricsFaceClientCallback.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "FaceAcquiredInfo",
+        "FaceError",
+        "OptionalUint64",
+        "Status",
+        "UserHandle",
+    ],
+    gen_java: true,
+}
+
diff --git a/biometrics/face/1.0/IBiometricsFace.hal b/biometrics/face/1.0/IBiometricsFace.hal
new file mode 100644
index 0000000..fbdb210
--- /dev/null
+++ b/biometrics/face/1.0/IBiometricsFace.hal
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+package android.hardware.biometrics.face@1.0;
+
+import IBiometricsFaceClientCallback;
+
+// TODO(b/78538290): Update comments with state machine transitions when ready.
+// TODO(b/78537981): Update comments with callback interaction contract.
+// TODO(b/79496983): Update comments with status returns fully enumerated.
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace {
+
+    /**
+     * Sets the current client callback.
+     *
+     * Registers a user function that must receive notifications from the HAL.
+     * There is usually only one client (FaceService). This call must block
+     * if the HAL state machine is in busy state until the HAL leaves the
+     * busy state.
+     *
+     * All callback methods pass a deviceId to differentiate callback
+     * invocations in the case where multiple sensors exist.
+     *
+     * @param clientCallback The client defined callback to register.
+     * @return result, with its "value" parameter representing a "deviceId",
+     *     which must be unique for a given sensor.
+     */
+    @callflow(next={"setActiveUser"})
+    @entry
+    setCallback(IBiometricsFaceClientCallback clientCallback)
+        generates (OptionalUint64 result);
+
+    /**
+     * Sets the active user, which all subsequent HAL operations are applied to.
+     *
+     * HAL service implementors must ensure that operations are restricted to
+     * the given user. Clients must not call any part of this interface, except
+     * for setCallback(), without first having set an active user. The
+     * implementation is responsible for cancelling the current operation and
+     * returning to the idle state. Calling this method with the same userId
+     * should have no effect on the state machine.
+     *
+     * @param userId A non-negative user identifier that must be unique and
+     *     persistent for a given user.
+     * @param storePath filesystem path to the template storage directory.
+     */
+    @callflow(next={"authenticate", "preEnroll", "enumerate", "remove"})
+    setActiveUser(int32_t userId, string storePath) generates (Status status);
+
+    /**
+     * Begins a pre-enrollment request.
+     *
+     * Generates a unique and cryptographically secure random token used to
+     * indicate the start of an enrollment transaction. preEnroll() and
+     * postEnroll() specify a pin/pattern/password cleared time window where
+     * enrollment is allowed.
+     *
+     * preEnroll() generates a challenge which must then be wrapped by the
+     * gatekeeper after verifying a successful strong authentication attempt,
+     * which generates a Hardware Authentication Token. The challenge prevents
+     * spoofing and replay attacks and ensures that we only update a user’s face
+     * template if the operation was preceded by some kind of strong credential
+     * confirmation (e.g. device password).
+     *
+     * @return result, with its "value" parameter representing a "challenge": a
+     *     unique and cryptographically secure random token.
+     */
+    @callflow(next={"enroll", "postEnroll"})
+    preEnroll() generates (OptionalUint64 result);
+
+    /**
+     * Enrolls a user's face.
+     *
+     * Note that this interface permits implementations where multiple faces can
+     * be enrolled for a single user. However, allowing multiple faces to be
+     * enrolled can be a severe security vulnerability and hence, most
+     * implementations must ensure that only a single face be enrolled at a
+     * given time. Multi-enrollment must only be used where there is a clear
+     * necessity for a shared use case, e.g. TVs or cars.
+     *
+     * Note that the Hardware Authentication Token must still be valid after
+     * this call, and must be explicitly invalidated by a call to postEnroll().
+     * This allows clients to immediately reattempt enrollment (for example, if
+     * a user wasn’t satisfied with their enrollment) without having to go
+     * through another strong authentication flow.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+     * method.
+     *
+     * @param hat A valid Hardware Authentication Token, generated as a result
+     *     of a preEnroll() challenge being wrapped by the gatekeeper after a
+     *     sucessful strong authentication request.
+     * @param timeoutSec A timeout in seconds, after which this enrollment
+     *     attempt is cancelled. Note that the client still needs to
+     *     call postEnroll() to terminate the enrollment session.
+     * @return status The status of this method call.
+     */
+    @callflow(next={"cancel", "enroll", "postEnroll", "remove"})
+    enroll(vec<uint8_t> hat, uint32_t timeoutSec) generates (Status status);
+
+    /**
+     * Finishes the enrollment session and invalidates the challenge generated
+     * by preEnroll().
+     *
+     * Clients must call this method once enrollment is complete, and the user's
+     * face template no longer needs to be updated.
+     *
+     * @return status The status of this method call.
+     */
+    @callflow(next={"authenticate", "setActiveUser", "enumerate", "remove"})
+    postEnroll() generates (Status status);
+
+    /**
+     * Returns an identifier associated with the current face set.
+     *
+     * The authenticator ID must change whenever a new face is enrolled. The
+     * authenticator ID must not be changed when a face is deleted. The
+     * authenticator ID must be an entropy-encoded random number which all
+     * current templates are tied to. The authenticator ID must be immutable
+     * outside of an active enrollment window to prevent replay attacks.
+     *
+     * @return result, with its value parameter representing an
+     *     "authenticatorId": an identifier associated to the user's current
+     *     face enrollment.
+     */
+    @callflow(next={"authenticate"})
+    getAuthenticatorId() generates (OptionalUint64 result);
+
+    /**
+     * Cancels a pending enrollment or authentication request.
+     *
+     * @return status The status of this method call.
+     */
+    @callflow(next={"authenticate", "enroll", "enumerate", "remove",
+        "setActiveUser"})
+    cancel() generates (Status status);
+
+    /**
+     * Enumerates all face templates associated with the active user.
+     *
+     * The onEnumerate() callback method is invoked once for each face template
+     * found.
+     *
+     * @return status The status of this method call.
+     */
+    @callflow(next={"remove", "enroll", "authenticate", "setActiveUser"})
+    enumerate() generates (Status status);
+
+    /**
+     * Removes a face template or all face templates associated with the active
+     * user.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onRemoved() method.
+     *
+     * @param faceId The id correpsonding to the face to be removed; or 0 if all
+     *    faces are to be removed.
+     * @return status The status of this method call.
+     */
+    @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId",
+        "setActiveUser"})
+    remove(uint32_t faceId) generates (Status status);
+
+    /**
+     * Authenticates the active user.
+     *
+     * An optional operationId can be specified as a token from the transaction
+     * being authorized.
+     *
+     * @param operationId A non-zero operation id associated with a crypto
+     * object instance; or 0 if not being used.
+     * @return status The status of this method call.
+     */
+    @callflow(next={"cancel", "preEnroll", "remove"})
+    authenticate(uint64_t operationId) generates (Status status);
+};
diff --git a/biometrics/face/1.0/IBiometricsFaceClientCallback.hal b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal
new file mode 100644
index 0000000..93848c5
--- /dev/null
+++ b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+package android.hardware.biometrics.face@1.0;
+
+/**
+ * This callback interface is used by clients to recieve updates from the face
+ * HAL.
+ */
+interface IBiometricsFaceClientCallback {
+
+    /**
+     * A callback invoked when one enrollment step has been completed.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this enrollment step.
+     * @param faceId The id of the face template being enrolled.
+     * @param userId The active user id for the template being enrolled.
+     * @param remaining The number of remaining steps before enrolllment is
+     *     complete or 0 if enrollment has completed successfully.
+     */
+    oneway onEnrollResult(uint64_t deviceId, uint32_t faceId, int32_t userId,
+        uint32_t remaining);
+
+    /**
+     * A callback invoked when a face has been successfully authenticated.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this autentication attempt.
+     * @param faceId The id of the face template that passed the authentication
+     *     challenge.
+     * @param userId The active user id for the authenticated face.
+     * @param token The hardware authentication token associated with this
+     *     authenticate operation.
+     */
+    oneway onAuthenticated(uint64_t deviceId, uint32_t faceId, int32_t userId,
+        vec<uint8_t> token);
+
+    /**
+     * A callback invoked when a face is acquired.
+     *
+     * If a non-critical, recoverable error occurs during an enrollment or
+     * authentication attempt, the HAL implementation must invoke this callback
+     * to allow clients to inform the user that some actionable change must be
+     * made.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that acquired a face.
+     * @param userId The id of the active user associated with the attempted
+     *     face acquisition.
+     * @param acquiredInfo A message about the quality of the acquired image.
+     * @param vendorCode An optional vendor-specific message. This is only valid
+     *     when acquiredInfo == FaceAcquiredInfo.VENDOR. This message is opaque
+     *     to the framework, and vendors must provide code to handle it. For
+     *     example this can be used to guide enrollment in Settings or provide
+     *     a message during authentication that is vendor-specific. The vendor
+     *     is expected to provide help strings to cover all known values.
+     */
+     oneway onAcquired(uint64_t deviceId, int32_t userId,
+         FaceAcquiredInfo acquiredInfo, int32_t vendorCode);
+
+    /**
+     * A callback invoked when an error has occured.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service where this error occured.
+     * @param userId The id of the active user when the error occured, or
+     *     UserHandle::NONE if an active user had not been set yet.
+     * @param error A message about the error that occurred.
+     * @param vendorCode An optional, vendor-speicifc error message. Only valid
+     *     when error == FaceError.VENDOR. This message is opaque to the
+     *     framework, and vendors must provide code to handle it. For example,
+     *     this scan be used to show the user an error message specific to the
+     *     device. The vendor is expected to provide error strings to cover
+     *     all known values.
+     */
+    oneway onError(uint64_t deviceId, int32_t userId, FaceError error,
+        int32_t vendorCode);
+
+    /**
+     * A callback invoked when a face template has been removed.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this removal.
+     * @param faceId The id of the face template that was removed.
+     * @param userId The active user id for the removed face template.
+     * @param remaining The number of face templates remaining after this
+     *     removal, or 0 if there are no more.
+     */
+    oneway onRemoved(uint64_t deviceId, uint32_t faceId, int32_t userId,
+        uint32_t remaining);
+
+    /**
+     * A callback invoked to enumerate all current face templates.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this enumeration.
+     * @param faceIds A list of ids of all currently enrolled face templates.
+     * @param userId The active user id for the enumerated face template.
+     */
+    oneway onEnumerate(uint64_t deviceId, vec<uint32_t> faceIds,
+        int32_t userId);
+};
diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal
new file mode 100644
index 0000000..08af919
--- /dev/null
+++ b/biometrics/face/1.0/types.hal
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+package android.hardware.biometrics.face@1.0;
+
+/*
+ * In the event setActiveUser is not called, all error messages will return
+ * this userId.
+ */
+enum UserHandle : int32_t {
+    NONE = -1
+};
+
+/**
+ * Status codes returned directly by the HIDL method calls upon critical errors
+ * where the callback cannot be invoked. Most errors should sent through the
+ * onError callback using one of the FaceErrors below.
+ */
+enum Status : uint32_t {
+    /**
+     * The method was invoked successfully.
+     */
+    OK = 0,
+
+    /**
+     * One of the arguments to the method call is invalid.
+     */
+    ILLEGAL_ARGUMENT = 1,
+
+    /**
+     * This face HAL does not support this operation.
+     */
+    OPERATION_NOT_SUPPORTED = 2,
+
+    /**
+     * The HAL has encountered an internal error and cannot complete the request.
+     */
+    INTERNAL_ERROR = 3
+};
+
+/**
+ * Face errors represent events that can't be immediately recovered by user
+ * intervention. These are returned in the onError callback.
+ *
+ * Upon receiving a face error, clients must terminate the current operation and
+ * notify the user where possible.
+ */
+enum FaceError : int32_t {
+
+    /**
+     * A hardware error has occured that cannot be resolved. Try again later.
+     */
+    HW_UNAVAILABLE = 1,
+
+    /**
+     * The current enroll or authenticate operation could not be completed;
+     * the sensor was unable to process the current image.
+     */
+    UNABLE_TO_PROCESS = 2,
+
+    /**
+     * The current operation took too long to complete. This is intended to
+     * prevent programs from blocking the face HAL indefinitely. The timeout is
+     * framework and sensor-specific, but is generally on the order of 30
+     * seconds.
+     */
+    TIMEOUT = 3,
+
+    /**
+     * The current operation could not be completed because there is not enough
+     * storage space remaining to do so.
+     */
+    NO_SPACE = 4,
+
+    /**
+     * The current operation has been cancelled. This may happen if a new
+     * request (authenticate, remove) is initiated while an on-going operation
+     * is in progress, or if cancel() was called.
+     */
+    CANCELED = 5,
+
+    /**
+     * The current remove operation could not be completed; the face template
+     * provided could not be removed.
+     */
+    UNABLE_TO_REMOVE = 6,
+
+    /**
+     * Face authentication is locked out due to too many unsuccessful attempts.
+     */
+    LOCKOUT = 7,
+
+    /**
+     * Used to enable a vendor-specific error message.
+     */
+    VENDOR = 8,
+};
+
+/**
+ * Face acquisition information provides feedback for the current enrollment
+ * or authentication operation.
+ *
+ * This information indicates that the user can take immediate action to resolve
+ * an issue, and clients must ensure that this information is surfaced to the
+ * user.
+ */
+enum FaceAcquiredInfo : int32_t {
+
+    /**
+     * The face acquired was good; no further user interaction is necessary.
+     */
+    GOOD = 0,
+
+    /**
+     * The face data acquired was too noisy or did not have sufficient detail.
+     * This is a catch-all for all acquisition errors not captured by the other
+     * constants.
+     */
+    INSUFFICIENT = 1,
+
+    /**
+     * Because there was too much ambient light, the captured face data was too
+     * bright. It's reasonable to return this after multiple
+     * FaceAcquiredInfo.INSUFFICIENT.
+     *
+     * The user is expected to take action to retry the operation in better
+     * lighting conditions when this is returned.
+     */
+    TOO_BRIGHT = 2,
+
+    /**
+     * Because there was not enough illumination, the captured face data was too
+     * dark. It's reasonable to return this after multiple
+     * FaceAcquiredInfo.INSUFFICIENT.
+     *
+     * The user is expected to take action to retry the operation in better
+     * lighting conditions when this is returned.
+     */
+    TOO_DARK = 3,
+
+    /**
+     * The detected face is too close to the sensor, and the image cannot be
+     * processed.
+     *
+     * The user is expected to be informed to move further from the sensor when
+     * this is returned.
+     */
+    TOO_CLOSE = 4,
+
+    /**
+     * The detected face is too small, as the user might be too far away from
+     * the sensor.
+     *
+     * The user is expected to be informed to move closer to the sensor when
+     * this is returned.
+     */
+    TOO_FAR = 5,
+
+    /**
+     * Only the upper part of the face was detected. The sensor's field of view
+     * is too high.
+     *
+     * The user should be informed to move up with respect to the sensor when
+     * this is returned.
+     */
+    FACE_TOO_HIGH = 6,
+
+    /**
+     * Only the lower part of the face was detected. The sensor's field of view
+     * is too low.
+     *
+     * The user should be informed to move down with respect to the sensor when
+     * this is returned.
+     */
+    FACE_TOO_LOW = 7,
+
+    /**
+     * Only the right part of the face was detected. The sensor's field of view
+     * is too far right.
+     *
+     * The user should be informed to move to the right with respect to the
+     * sensor when this is returned.
+     */
+    FACE_TOO_RIGHT = 8,
+
+    /**
+     * Only the left part of the face was detected. The sensor's field of view
+     * is too far left.
+     *
+     * The user should be informed to move to the left with respect to the
+     * sensor when this is returned.
+     */
+    FACE_TOO_LEFT = 9,
+
+    /**
+     * The user's face was directed away from the sensor. The user should be
+     * informed to face the sensor when this is returned.
+     */
+    POOR_GAZE = 10,
+
+    /**
+     * No face was detected within the sensor's field of view.
+     *
+     * The user should be informed to point the sensor to a face when this is
+     * returned.
+     */
+    NOT_DETECTED = 11,
+
+    /**
+     * Too much motion was detected.
+     *
+     * The user should be informed to keep their face steady relative to the
+     * sensor.
+     */
+    TOO_MUCH_MOTION = 12,
+
+    /**
+     * The sensor needs to be recalibrated.
+     */
+    RECALIBRATE = 13,
+
+    /**
+     * Used to enable a vendor-specific acquisition message.
+     */
+    VENDOR = 14
+};
+
+/**
+ * Result structure with an additional uint64_t field. See documentation in
+ * setCallback(), preEnroll(), and getAuthenticatorId() for usage of the value.
+ */
+struct OptionalUint64 {
+    /**
+     * The return status.
+     */
+    Status status;
+
+    /**
+     * This value is only meaningful if status is OK.
+     */
+    uint64_t value;
+};
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 094b35d..4e610a7 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -70,6 +70,18 @@
 
 include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/clear_vars.mk
+LOCAL_MODULE := framework_compatibility_matrix.current.xml
+LOCAL_MODULE_STEM := compatibility_matrix.current.xml
+LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
+LOCAL_KERNEL_CONFIG_DATA_PATHS := \
+    4.4.0:$(my_kernel_config_data)/android-4.4 \
+    4.9.0:$(my_kernel_config_data)/android-4.9 \
+    4.14.0:$(my_kernel_config_data)/android-4.14 \
+
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
+
 my_kernel_config_data :=
 
 # Framework Compatibility Matrix (common to all FCM versions)
@@ -120,6 +132,7 @@
     framework_compatibility_matrix.1.xml \
     framework_compatibility_matrix.2.xml \
     framework_compatibility_matrix.3.xml \
+    framework_compatibility_matrix.current.xml \
     framework_compatibility_matrix.device.xml
 
 # Phony target that installs all framework compatibility matrix files
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
new file mode 100644
index 0000000..1b9ab33
--- /dev/null
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -0,0 +1,458 @@
+<compatibility-matrix version="1.0" type="framework" level="4">
+    <hal format="hidl" optional="false">
+        <name>android.hardware.audio</name>
+        <version>4.0</version>
+        <interface>
+            <name>IDevicesFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.audio.effect</name>
+        <version>4.0</version>
+        <interface>
+            <name>IEffectsFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.authsecret</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAuthSecret</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.audiocontrol</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAudioControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.evs</name>
+        <version>1.0</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.vehicle</name>
+        <version>2.0</version>
+        <interface>
+            <name>IVehicle</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <version>2.1</version>
+        <interface>
+            <name>IBiometricsFingerprint</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.bluetooth</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.bluetooth.a2dp</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothAudioOffload</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.boot</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBootControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.broadcastradio</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IBroadcastRadioFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.camera.provider</name>
+        <version>2.4</version>
+        <interface>
+            <name>ICameraProvider</name>
+            <regex-instance>[^/]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.cas</name>
+        <version>1.0</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.configstore</name>
+        <version>1.1</version>
+        <interface>
+            <name>ISurfaceFlingerConfigs</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.confirmationui</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.contexthub</name>
+        <version>1.0</version>
+        <interface>
+            <name>IContexthub</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.drm</name>
+        <version>1.0</version>
+        <interface>
+            <name>ICryptoFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>IDrmFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.drm</name>
+        <version>1.1</version>
+        <interface>
+            <name>ICryptoFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>IDrmFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.dumpstate</name>
+        <version>1.0</version>
+        <interface>
+            <name>IDumpstateDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.gatekeeper</name>
+        <version>1.0</version>
+        <interface>
+            <name>IGatekeeper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.gnss</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IGnss</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.allocator</name>
+        <version>2.0</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.composer</name>
+        <version>2.1</version>
+        <interface>
+            <name>IComposer</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.mapper</name>
+        <version>2.0</version>
+        <interface>
+            <name>IMapper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.health</name>
+        <version>2.0</version>
+        <interface>
+            <name>IHealth</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.ir</name>
+        <version>1.0</version>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.keymaster</name>
+        <version>3.0</version>
+        <version>4.0</version>
+        <interface>
+            <name>IKeymasterDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.keymaster</name>
+        <version>4.0</version>
+        <interface>
+            <name>IKeymasterDevice</name>
+            <instance>strongbox</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.light</name>
+        <version>2.0</version>
+        <interface>
+            <name>ILight</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.media.omx</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOmx</name>
+            <instance>default</instance>
+        </interface>
+        <interface>
+            <name>IOmxStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.memtrack</name>
+        <version>1.0</version>
+        <interface>
+            <name>IMemtrack</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.neuralnetworks</name>
+        <version>1.0</version>
+        <interface>
+            <name>IDevice</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.nfc</name>
+        <version>1.1</version>
+        <interface>
+            <name>INfc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.oemlock</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOemLock</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.power</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IPower</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IRadio</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+        <interface>
+            <name>ISap</name>
+            <instance>slot1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio.config</name>
+        <version>1.0</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.renderscript</name>
+        <version>1.0</version>
+        <interface>
+            <name>IDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.secure_element</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISecureElement</name>
+            <regex-instance>eSE[1-9][0-9]*</regex-instance>
+            <regex-instance>SIM[1-9][0-9]*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.sensors</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.soundtrigger</name>
+        <version>2.0-1</version>
+        <interface>
+            <name>ISoundTriggerHw</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tetheroffload.config</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffloadConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tetheroffload.control</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffloadControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.thermal</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IThermal</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tv.cec</name>
+        <version>1.0</version>
+        <interface>
+            <name>IHdmiCec</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tv.input</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITvInput</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.usb</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IUsb</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.usb.gadget</name>
+        <version>1.0</version>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.vibrator</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IVibrator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.vr</name>
+        <version>1.0</version>
+        <interface>
+            <name>IVr</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.weaver</name>
+        <version>1.0</version>
+        <interface>
+            <name>IWeaver</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IWifi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.hostapd</name>
+        <version>1.0</version>
+        <interface>
+            <name>IHostapd</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.offload</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffload</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.supplicant</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>ISupplicant</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</compatibility-matrix>
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index 010a46d..608ee70 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -472,6 +472,16 @@
   }
 }
 
+/*
+ * SchedulingCapabilities:
+ * Verifies that 2018+ hardware supports Scheduling capabilities.
+ */
+TEST_F(GnssHalTest, SchedulingCapabilities) {
+    if (info_called_count_ > 0 && last_info_.yearOfHw >= 2018) {
+        EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::SCHEDULING);
+    }
+}
+
 int main(int argc, char** argv) {
   ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 2f531b4..43a5378 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -25,21 +25,19 @@
 namespace V2_1 {
 namespace vts {
 
-Composer::Composer() {
-    mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>();
-    init();
-}
+Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
 
-Composer::Composer(const std::string& name) {
-    mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name);
-    init();
-}
+Composer::Composer(const std::string& name)
+    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
 
-void Composer::init() {
-    ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
+Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) {
+    // ASSERT_* can only be used in functions returning void.
+    [this] {
+        ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
 
-    std::vector<IComposer::Capability> capabilities = getCapabilities();
-    mCapabilities.insert(capabilities.begin(), capabilities.end());
+        std::vector<IComposer::Capability> capabilities = getCapabilities();
+        mCapabilities.insert(capabilities.begin(), capabilities.end());
+    }();
 }
 
 sp<IComposer> Composer::getRaw() const {
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index 8d5493e..c97be76 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -57,10 +57,10 @@
     std::unique_ptr<ComposerClient> createClient();
 
    protected:
-    sp<IComposer> mComposer;
+    explicit Composer(const sp<IComposer>& composer);
 
    private:
-    void init();
+    const sp<IComposer> mComposer;
 
     std::unordered_set<IComposer::Capability> mCapabilities;
 };
@@ -68,7 +68,7 @@
 // A wrapper to IComposerClient.
 class ComposerClient {
    public:
-    ComposerClient(const sp<IComposerClient>& client);
+    explicit ComposerClient(const sp<IComposerClient>& client);
     ~ComposerClient();
 
     sp<IComposerClient> getRaw() const;
@@ -116,7 +116,7 @@
     std::unordered_map<Display, DisplayResource> mDisplayResources;
 
    private:
-    sp<IComposerClient> mClient;
+    const sp<IComposerClient> mClient;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index 6a32071..f2596a4 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -27,32 +27,31 @@
 namespace V2_2 {
 namespace vts {
 
-using android::hardware::details::canCastInterface;
-using android::hardware::details::getDescriptor;
-using android::hardware::graphics::composer::V2_2::IComposerClient;
+using details::canCastInterface;
+using details::getDescriptor;
 
-std::unique_ptr<ComposerClient_v2_2> Composer_v2_2::createClient_v2_2() {
-    std::unique_ptr<ComposerClient_v2_2> client;
-    mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+std::unique_ptr<ComposerClient> Composer::createClient() {
+    std::unique_ptr<ComposerClient> client;
+    getRaw()->createClient([&](const auto& tmpError, const auto& tmpClient) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
         ALOGV("tmpClient is a %s", getDescriptor(&(*tmpClient)).c_str());
         ASSERT_TRUE(canCastInterface(
             &(*tmpClient), "android.hardware.graphics.composer@2.2::IComposerClient", false))
             << "Cannot create 2.2 IComposerClient";
-        client = std::make_unique<ComposerClient_v2_2>(IComposerClient::castFrom(tmpClient, true));
+        client = std::make_unique<ComposerClient>(IComposerClient::castFrom(tmpClient, true));
     });
 
     return client;
 }
 
-sp<V2_2::IComposerClient> ComposerClient_v2_2::getRaw() const {
-    return mClient_v2_2;
+sp<IComposerClient> ComposerClient::getRaw() const {
+    return mClient;
 }
 
-std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient_v2_2::getPerFrameMetadataKeys(
+std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient::getPerFrameMetadataKeys(
     Display display) {
     std::vector<IComposerClient::PerFrameMetadataKey> keys;
-    mClient_v2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+    mClient->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR metadata keys";
         keys = tmpKeys;
     });
@@ -60,43 +59,42 @@
     return keys;
 }
 
-void ComposerClient_v2_2::execute_v2_2(V2_1::vts::TestCommandReader* reader,
-                                       V2_2::CommandWriterBase* writer) {
+void ComposerClient::execute(V2_1::vts::TestCommandReader* reader, CommandWriterBase* writer) {
     bool queueChanged = false;
     uint32_t commandLength = 0;
     hidl_vec<hidl_handle> commandHandles;
     ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
 
     if (queueChanged) {
-        auto ret = mClient_v2_2->setInputCommandQueue(*writer->getMQDescriptor());
+        auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
         ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
         return;
     }
 
-    mClient_v2_2->executeCommands(commandLength, commandHandles,
-                                  [&](const auto& tmpError, const auto& tmpOutQueueChanged,
-                                      const auto& tmpOutLength, const auto& tmpOutHandles) {
-                                      ASSERT_EQ(Error::NONE, tmpError);
+    mClient->executeCommands(commandLength, commandHandles,
+                             [&](const auto& tmpError, const auto& tmpOutQueueChanged,
+                                 const auto& tmpOutLength, const auto& tmpOutHandles) {
+                                 ASSERT_EQ(Error::NONE, tmpError);
 
-                                      if (tmpOutQueueChanged) {
-                                          mClient_v2_2->getOutputCommandQueue(
-                                              [&](const auto& tmpError, const auto& tmpDescriptor) {
-                                                  ASSERT_EQ(Error::NONE, tmpError);
-                                                  reader->setMQDescriptor(tmpDescriptor);
-                                              });
-                                      }
+                                 if (tmpOutQueueChanged) {
+                                     mClient->getOutputCommandQueue(
+                                         [&](const auto& tmpError, const auto& tmpDescriptor) {
+                                             ASSERT_EQ(Error::NONE, tmpError);
+                                             reader->setMQDescriptor(tmpDescriptor);
+                                         });
+                                 }
 
-                                      ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
-                                      reader->parse();
-                                  });
+                                 ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+                                 reader->parse();
+                             });
 }
 
-Display ComposerClient_v2_2::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
-                                                      PixelFormat formatHint,
-                                                      uint32_t outputBufferSlotCount,
-                                                      PixelFormat* outFormat) {
+Display ComposerClient::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+                                                 PixelFormat formatHint,
+                                                 uint32_t outputBufferSlotCount,
+                                                 PixelFormat* outFormat) {
     Display display = 0;
-    mClient_v2_2->createVirtualDisplay_2_2(
+    mClient->createVirtualDisplay_2_2(
         width, height, formatHint, outputBufferSlotCount,
         [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) {
             ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display";
@@ -110,29 +108,27 @@
     return display;
 }
 
-bool ComposerClient_v2_2::getClientTargetSupport_2_2(Display display, uint32_t width,
-                                                     uint32_t height, PixelFormat format,
-                                                     Dataspace dataspace) {
-    Error error =
-        mClient_v2_2->getClientTargetSupport_2_2(display, width, height, format, dataspace);
+bool ComposerClient::getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
+                                                PixelFormat format, Dataspace dataspace) {
+    Error error = mClient->getClientTargetSupport_2_2(display, width, height, format, dataspace);
     return error == Error::NONE;
 }
 
-void ComposerClient_v2_2::setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) {
-    Error error = mClient_v2_2->setPowerMode_2_2(display, mode);
+void ComposerClient::setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) {
+    Error error = mClient->setPowerMode_2_2(display, mode);
     ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set power mode";
 }
 
-void ComposerClient_v2_2::setReadbackBuffer(Display display, const native_handle_t* buffer,
-                                            int32_t /* releaseFence */) {
+void ComposerClient::setReadbackBuffer(Display display, const native_handle_t* buffer,
+                                       int32_t /* releaseFence */) {
     // Ignoring fence, HIDL doesn't care
-    Error error = mClient_v2_2->setReadbackBuffer(display, buffer, nullptr);
+    Error error = mClient->setReadbackBuffer(display, buffer, nullptr);
     ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
 }
 
-void ComposerClient_v2_2::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
-                                                      Dataspace* outDataspace) {
-    mClient_v2_2->getReadbackBufferAttributes(
+void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                                 Dataspace* outDataspace) {
+    mClient->getReadbackBufferAttributes(
         display,
         [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
             ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
@@ -141,42 +137,41 @@
         });
 }
 
-void ComposerClient_v2_2::getReadbackBufferFence(Display display, int32_t* outFence) {
+void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) {
     hidl_handle handle;
-    mClient_v2_2->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
+    mClient->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence";
         handle = tmpHandle;
     });
     *outFence = 0;
 }
 
-std::vector<ColorMode> ComposerClient_v2_2::getColorModes(Display display) {
+std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
     std::vector<ColorMode> modes;
-    mClient_v2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
+    mClient->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to get color modes";
         modes = tmpModes;
     });
     return modes;
 }
 
-std::vector<RenderIntent> ComposerClient_v2_2::getRenderIntents(Display display, ColorMode mode) {
+std::vector<RenderIntent> ComposerClient::getRenderIntents(Display display, ColorMode mode) {
     std::vector<RenderIntent> intents;
-    mClient_v2_2->getRenderIntents(
-        display, mode, [&](const auto& tmpError, const auto& tmpIntents) {
-            ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents";
-            intents = tmpIntents;
-        });
+    mClient->getRenderIntents(display, mode, [&](const auto& tmpError, const auto& tmpIntents) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents";
+        intents = tmpIntents;
+    });
     return intents;
 }
 
-void ComposerClient_v2_2::setColorMode(Display display, ColorMode mode, RenderIntent intent) {
-    Error error = mClient_v2_2->setColorMode_2_2(display, mode, intent);
+void ComposerClient::setColorMode(Display display, ColorMode mode, RenderIntent intent) {
+    Error error = mClient->setColorMode_2_2(display, mode, intent);
     ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set color mode";
 }
 
-std::array<float, 16> ComposerClient_v2_2::getDataspaceSaturationMatrix(Dataspace dataspace) {
+std::array<float, 16> ComposerClient::getDataspaceSaturationMatrix(Dataspace dataspace) {
     std::array<float, 16> matrix;
-    mClient_v2_2->getDataspaceSaturationMatrix(
+    mClient->getDataspaceSaturationMatrix(
         dataspace, [&](const auto& tmpError, const auto& tmpMatrix) {
             ASSERT_EQ(Error::NONE, tmpError) << "failed to get datasapce saturation matrix";
             std::copy_n(tmpMatrix.data(), matrix.size(), matrix.begin());
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 1c6d7ae..2633021 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -36,36 +36,31 @@
 namespace V2_2 {
 namespace vts {
 
-using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
-using android::hardware::graphics::common::V1_1::PixelFormat;
-using android::hardware::graphics::common::V1_1::RenderIntent;
-using android::hardware::graphics::composer::V2_2::IComposer;
-using android::hardware::graphics::composer::V2_2::IComposerClient;
+using common::V1_0::Hdr;
+using common::V1_1::ColorMode;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
 
-class ComposerClient_v2_2;
+class ComposerClient;
 
-// Only thing I need for Composer_v2_2 is to create a v2_2 ComposerClient
-// Everything else is the same
-class Composer_v2_2 : public V2_1::vts::Composer {
+// A wrapper to IComposer.
+class Composer : public V2_1::vts::Composer {
    public:
-    Composer_v2_2() : V2_1::vts::Composer(){};
-    explicit Composer_v2_2(const std::string& name) : V2_1::vts::Composer(name){};
+    using V2_1::vts::Composer::Composer;
 
-    std::unique_ptr<ComposerClient_v2_2> createClient_v2_2();
+    std::unique_ptr<ComposerClient> createClient();
 };
 
 // A wrapper to IComposerClient.
-class ComposerClient_v2_2
-    : public android::hardware::graphics::composer::V2_1::vts::ComposerClient {
+class ComposerClient : public V2_1::vts::ComposerClient {
    public:
-    ComposerClient_v2_2(const sp<IComposerClient>& client)
-        : V2_1::vts::ComposerClient(client), mClient_v2_2(client){};
+    explicit ComposerClient(const sp<IComposerClient>& client)
+        : V2_1::vts::ComposerClient(client), mClient(client) {}
 
-    sp<V2_2::IComposerClient> getRaw() const;
+    sp<IComposerClient> getRaw() const;
 
-    void execute_v2_2(V2_1::vts::TestCommandReader* reader, V2_2::CommandWriterBase* writer);
+    void execute(V2_1::vts::TestCommandReader* reader, CommandWriterBase* writer);
 
     std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(Display display);
 
@@ -73,7 +68,7 @@
                                      uint32_t outputBufferSlotCount, PixelFormat* outFormat);
     bool getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
                                     PixelFormat format, Dataspace dataspace);
-    void setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode);
+    void setPowerMode_2_2(Display display, IComposerClient::PowerMode mode);
     void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
     void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
                                      Dataspace* outDataspace);
@@ -86,7 +81,7 @@
     std::array<float, 16> getDataspaceSaturationMatrix(Dataspace dataspace);
 
    private:
-    sp<V2_2::IComposerClient> mClient_v2_2;
+    const sp<IComposerClient> mClient;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 23bf558..e3b7f55 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -32,17 +32,15 @@
 namespace vts {
 namespace {
 
-using android::hardware::graphics::common::V1_0::BufferUsage;
-using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
-using android::hardware::graphics::common::V1_1::PixelFormat;
-using android::hardware::graphics::common::V1_1::RenderIntent;
-using android::hardware::graphics::composer::V2_2::IComposerClient;
-using android::hardware::graphics::mapper::V2_1::IMapper;
-using android::hardware::graphics::mapper::V2_1::vts::Gralloc;
-using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
+using common::V1_0::BufferUsage;
+using common::V1_0::ColorTransform;
+using common::V1_0::Transform;
+using common::V1_1::ColorMode;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
+using mapper::V2_1::IMapper;
+using mapper::V2_1::vts::Gralloc;
 
 // Test environment for graphics.composer
 class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -65,9 +63,9 @@
    protected:
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(
-            mComposer = std::make_unique<Composer_v2_2>(
+            mComposer = std::make_unique<Composer>(
                 GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
-        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient_v2_2());
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
 
         mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
         mComposerClient->registerCallback(mComposerCallback);
@@ -96,8 +94,8 @@
     // use the slot count usually set by SF
     static constexpr uint32_t kBufferSlotCount = 64;
 
-    std::unique_ptr<Composer_v2_2> mComposer;
-    std::unique_ptr<ComposerClient_v2_2> mComposerClient;
+    std::unique_ptr<Composer> mComposer;
+    std::unique_ptr<ComposerClient> mComposerClient;
     sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
     // the first display and is assumed never to be removed
     Display mPrimaryDisplay;
@@ -125,7 +123,7 @@
 
         ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
 
-        mWriter = std::make_unique<V2_2::CommandWriterBase>(1024);
+        mWriter = std::make_unique<CommandWriterBase>(1024);
         mReader = std::make_unique<V2_1::vts::TestCommandReader>();
     }
 
@@ -143,9 +141,9 @@
         return mGralloc->allocate(info);
     }
 
-    void execute() { mComposerClient->execute_v2_2(mReader.get(), mWriter.get()); }
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
 
-    std::unique_ptr<V2_2::CommandWriterBase> mWriter;
+    std::unique_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
 
    private:
diff --git a/graphics/composer/2.3/Android.bp b/graphics/composer/2.3/Android.bp
new file mode 100644
index 0000000..23061dd
--- /dev/null
+++ b/graphics/composer/2.3/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.composer@2.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IComposer.hal",
+        "IComposerClient.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/graphics/composer/2.3/IComposer.hal b/graphics/composer/2.3/IComposer.hal
new file mode 100644
index 0000000..90b2427
--- /dev/null
+++ b/graphics/composer/2.3/IComposer.hal
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.composer@2.3;
+
+import IComposerClient;
+
+import @2.1::Error;
+import @2.2::IComposer;
+
+interface IComposer extends @2.2::IComposer {
+
+    /**
+     * Creates a v2.3 client of the composer. Supersedes @2.1::createClient.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *         NO_RESOURCES when the client could not be created.
+     * @return client is the newly created client.
+     */
+    @entry
+    @callflow(next="*")
+    createClient_2_3() generates (Error error, IComposerClient client);
+
+};
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
new file mode 100644
index 0000000..77dd3ee
--- /dev/null
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.composer@2.3;
+
+import @2.2::IComposerClient;
+import @2.1::Display;
+import @2.1::Error;
+
+interface IComposerClient extends @2.2::IComposerClient {
+
+    /**
+     * Returns the port and data that describe a physical display. The port is
+     * a unique number that identifies a physical connector (e.g. eDP, HDMI)
+     * for display output. The data blob is parsed to determine its format,
+     * typically EDID 1.3 as specified in VESA E-EDID Standard Release A
+     * Revision 1.
+     *
+     * @param display is the display to query.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         UNSUPPORTED when identification data is unavailable.
+     * @return port is the connector to which the display is connected.
+     * @return data is the EDID 1.3 blob identifying the display.
+     */
+    @callflow(next="*")
+    getDisplayIdentificationData(Display display)
+               generates (Error error,
+                          uint8_t port,
+                          vec<uint8_t> data);
+
+};
diff --git a/graphics/composer/2.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp
new file mode 100644
index 0000000..ad49ec3
--- /dev/null
+++ b/graphics/composer/2.3/default/Android.bp
@@ -0,0 +1,45 @@
+//
+// 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.
+//
+
+cc_binary {
+    name: "android.hardware.graphics.composer@2.3-service",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: ["service.cpp"],
+    init_rc: ["android.hardware.graphics.composer@2.3-service.rc"],
+    header_libs: [
+        "android.hardware.graphics.composer@2.3-passthrough",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.mapper@2.0",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwc2on1adapter",
+        "libhwc2onfbadapter",
+        "liblog",
+        "libsync",
+        "libutils",
+    ],
+}
diff --git a/graphics/composer/2.3/default/OWNERS b/graphics/composer/2.3/default/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/composer/2.3/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc
new file mode 100644
index 0000000..08e32d8
--- /dev/null
+++ b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc
@@ -0,0 +1,6 @@
+service vendor.hwcomposer-2-3 /vendor/bin/hw/android.hardware.graphics.composer@2.3-service
+    class hal animation
+    user system
+    group graphics drmrpc
+    capabilities SYS_NICE
+    onrestart restart surfaceflinger
diff --git a/graphics/composer/2.3/default/service.cpp b/graphics/composer/2.3/default/service.cpp
new file mode 100644
index 0000000..347d8be
--- /dev/null
+++ b/graphics/composer/2.3/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 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.
+ */
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.3/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_3::IComposer;
+using android::hardware::graphics::composer::V2_3::passthrough::HwcLoader;
+
+int main() {
+    // the conventional HAL might start binder services
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+    android::ProcessState::self()->startThreadPool();
+
+    // same as SF main thread
+    struct sched_param param = {0};
+    param.sched_priority = 2;
+    if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+    }
+
+    android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+    android::sp<IComposer> composer = HwcLoader::load();
+    if (composer == nullptr) {
+        return 1;
+    }
+    if (composer->registerAsService() != android::NO_ERROR) {
+        ALOGE("failed to register service");
+        return 1;
+    }
+
+    android::hardware::joinRpcThreadpool();
+
+    ALOGE("service is terminating");
+    return 1;
+}
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
new file mode 100644
index 0000000..234bc75
--- /dev/null
+++ b/graphics/composer/2.3/utils/OWNERS
@@ -0,0 +1,7 @@
+# Graphics team
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.3/utils/hal/Android.bp b/graphics/composer/2.3/utils/hal/Android.bp
new file mode 100644
index 0000000..aa46df1
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.3-hal",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.3",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.3",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.2-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.2-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h
new file mode 100644
index 0000000..8e11a5a
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <composer-hal/2.2/Composer.h>
+#include <composer-hal/2.3/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_2::hal::detail::ComposerImpl<Interface, Hal> {
+   public:
+    static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+        return std::make_unique<ComposerImpl>(std::move(hal));
+    }
+
+    explicit ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_2(std::move(hal)) {}
+
+    // IComposer 2.3 interface
+
+    Return<void> createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) override {
+        std::unique_lock<std::mutex> lock(mClientMutex);
+        if (!waitForClientDestroyedLocked(lock)) {
+            hidl_cb(Error::NO_RESOURCES, nullptr);
+            return Void();
+        }
+
+        sp<ComposerClient> client = ComposerClient::create(mHal.get()).release();
+        if (!client) {
+            hidl_cb(Error::NO_RESOURCES, nullptr);
+            return Void();
+        }
+
+        auto clientDestroyed = [this]() { onClientDestroyed(); };
+        client->setOnClientDestroyed(clientDestroyed);
+
+        mClient = client;
+        hidl_cb(Error::NONE, client);
+        return Void();
+    }
+
+   private:
+    using BaseType2_2 = V2_2::hal::detail::ComposerImpl<Interface, Hal>;
+    using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+
+    using BaseType2_1::mClient;
+    using BaseType2_1::mClientMutex;
+    using BaseType2_1::mHal;
+    using BaseType2_1::onClientDestroyed;
+    using BaseType2_1::waitForClientDestroyedLocked;
+};
+
+}  // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
new file mode 100644
index 0000000..e717d84
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interface, Hal> {
+   public:
+    static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+        auto client = std::make_unique<ComposerClientImpl>(hal);
+        return client->init() ? std::move(client) : nullptr;
+    }
+
+    ComposerClientImpl(Hal* hal) : BaseType2_2(hal) {}
+
+    // IComposerClient 2.3 interface
+
+    Return<void> getDisplayIdentificationData(
+        Display display, IComposerClient::getDisplayIdentificationData_cb hidl_cb) override {
+        uint8_t port = 0;
+        std::vector<uint8_t> data;
+        Error error = mHal->getDisplayIdentificationData(display, &port, &data);
+        hidl_cb(error, port, data);
+        return Void();
+    }
+
+   private:
+    using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+
+    using BaseType2_1::mHal;
+};
+
+}  // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
new file mode 100644
index 0000000..37ea0a3
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <composer-hal/2.2/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+using V2_1::Display;
+using V2_1::Error;
+
+class ComposerHal : public V2_2::hal::ComposerHal {
+   public:
+    virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                               std::vector<uint8_t>* outData) = 0;
+};
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/passthrough/Android.bp b/graphics/composer/2.3/utils/passthrough/Android.bp
new file mode 100644
index 0000000..3ae6b16
--- /dev/null
+++ b/graphics/composer/2.3/utils/passthrough/Android.bp
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.3-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    header_libs: [
+        "android.hardware.graphics.composer@2.2-passthrough",
+        "android.hardware.graphics.composer@2.3-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.2-passthrough",
+        "android.hardware.graphics.composer@2.3-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
new file mode 100644
index 0000000..53f2d1b
--- /dev/null
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-passthrough/2.2/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace passthrough {
+
+namespace detail {
+
+using V2_1::Display;
+using V2_1::Error;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
+   public:
+    Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                       std::vector<uint8_t>* outData) override {
+        if (!mDispatch.getDisplayIdentificationData) {
+            return Error::UNSUPPORTED;
+        }
+
+        uint32_t size = 0;
+        int32_t error =
+            mDispatch.getDisplayIdentificationData(mDevice, display, outPort, &size, nullptr);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        std::vector<uint8_t> data(size);
+        error =
+            mDispatch.getDisplayIdentificationData(mDevice, display, outPort, &size, data.data());
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        data.resize(size);
+        *outData = std::move(data);
+        return Error::NONE;
+    }
+
+   protected:
+    bool initDispatch() override {
+        if (!BaseType2_2::initDispatch()) {
+            return false;
+        }
+
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
+                                   &mDispatch.getDisplayIdentificationData);
+        return true;
+    }
+
+   private:
+    struct {
+        HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
+    } mDispatch = {};
+
+    using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1::mDevice;
+};
+
+}  // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+}  // namespace passthrough
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h
new file mode 100644
index 0000000..afef475
--- /dev/null
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.3/Composer.h>
+#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-passthrough/2.2/HwcLoader.h>
+#include <composer-passthrough/2.3/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace passthrough {
+
+class HwcLoader : public V2_2::passthrough::HwcLoader {
+   public:
+    static IComposer* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+
+        auto hal = createHalWithAdapter(module);
+        if (!hal) {
+            return nullptr;
+        }
+
+        return createComposer(std::move(hal)).release();
+    }
+
+    // create a ComposerHal instance
+    static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithModule(module) ? std::move(hal) : nullptr;
+    }
+
+    // create a ComposerHal instance, insert an adapter if necessary
+    static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+        bool adapted;
+        hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+        if (!device) {
+            return nullptr;
+        }
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+    }
+
+    // create an IComposer instance
+    static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+        return hal::Composer::create(std::move(hal));
+    }
+};
+
+}  // namespace passthrough
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
new file mode 100644
index 0000000..0553258
--- /dev/null
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -0,0 +1,41 @@
+//
+// 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.
+//
+
+cc_library_static {
+    name: "android.hardware.graphics.composer@2.3-vts",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "ComposerVts.cpp",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.1-vts",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-vts",
+        "android.hardware.graphics.composer@2.3",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+        "-DLOG_TAG=\"ComposerVts\"",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
new file mode 100644
index 0000000..f1d3a50
--- /dev/null
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include <composer-vts/2.3/ComposerVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace vts {
+
+using V2_1::Error;
+
+Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
+
+Composer::Composer(const std::string& name)
+    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
+
+Composer::Composer(const sp<IComposer>& composer)
+    : V2_2::vts::Composer(composer), mComposer(composer) {}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+    std::unique_ptr<ComposerClient> client;
+    mComposer->createClient_2_3([&client](const auto& tmpError, const auto& tmpClient) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+        client = std::make_unique<ComposerClient>(tmpClient);
+    });
+
+    return client;
+}
+
+bool ComposerClient::getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                                  std::vector<uint8_t>* outData) {
+    bool supported = true;
+    mClient->getDisplayIdentificationData(
+        display, [&](const auto& tmpError, const auto& tmpPort, const auto& tmpData) {
+            if (tmpError == Error::UNSUPPORTED) {
+                supported = false;
+                return;
+            }
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get display identification data";
+
+            *outPort = tmpPort;
+            *outData = tmpData;
+            ASSERT_FALSE(outData->empty()) << "data is empty";
+        });
+
+    return supported;
+}
+
+}  // namespace vts
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
new file mode 100644
index 0000000..103b85a
--- /dev/null
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace vts {
+
+using V2_1::Display;
+using V2_3::IComposer;
+using V2_3::IComposerClient;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer : public V2_2::vts::Composer {
+   public:
+    Composer();
+    explicit Composer(const std::string& name);
+
+    std::unique_ptr<ComposerClient> createClient();
+
+   protected:
+    explicit Composer(const sp<IComposer>& composer);
+
+   private:
+    const sp<IComposer> mComposer;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient : public V2_2::vts::ComposerClient {
+   public:
+    explicit ComposerClient(const sp<IComposerClient>& client)
+        : V2_2::vts::ComposerClient(client), mClient(client) {}
+
+    bool getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                      std::vector<uint8_t>* outData);
+
+   private:
+    const sp<IComposerClient> mClient;
+};
+
+}  // namespace vts
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
new file mode 100644
index 0000000..df696c9
--- /dev/null
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "VtsHalGraphicsComposerV2_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
+
+    // TODO(b/64437680): Assume these libs are always available on the device.
+    shared_libs: [
+        "libfmq",
+        "libhidltransport",
+        "libsync",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.1-vts",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-vts",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.3-vts",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+}
diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS
new file mode 100644
index 0000000..234bc75
--- /dev/null
+++ b/graphics/composer/2.3/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+# Graphics team
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
new file mode 100644
index 0000000..f4e34f0
--- /dev/null
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 "graphics_composer_hidl_hal_test@2.3"
+
+#include <algorithm>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.3/ComposerVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace vts {
+namespace {
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsComposerHidlEnvironment* Instance() {
+        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+   private:
+    GraphicsComposerHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+            mComposer = std::make_unique<Composer>(
+                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+
+        mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+
+        // explicitly disable vsync
+        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+        mComposerCallback->setVsyncAllowed(false);
+    }
+
+    void TearDown() override {
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+    }
+
+    std::unique_ptr<Composer> mComposer;
+    std::unique_ptr<ComposerClient> mComposerClient;
+    sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+
+   private:
+    Display waitForFirstDisplay() {
+        while (true) {
+            std::vector<Display> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+
+            return displays[0];
+        }
+    }
+};
+
+/**
+ * Test IComposerClient::getDisplayIdentificationData.
+ *
+ * TODO: Check that ports are unique for multiple displays.
+ */
+TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
+    uint8_t port0;
+    std::vector<uint8_t> data0;
+    if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) {
+        uint8_t port1;
+        std::vector<uint8_t> data1;
+        ASSERT_TRUE(mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port1, &data1));
+
+        ASSERT_EQ(port0, port1) << "ports are not stable";
+        ASSERT_TRUE(data0.size() == data1.size() &&
+                    std::equal(data0.begin(), data0.end(), data1.begin()))
+            << "data is not stable";
+    }
+}
+
+}  // namespace
+}  // namespace vts
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::composer::V2_3::vts::GraphicsComposerHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/health/2.0/README b/health/2.0/README
index dfd965a..9f77b83 100644
--- a/health/2.0/README
+++ b/health/2.0/README
@@ -48,16 +48,12 @@
 
     header_libs: ["libhealthd_headers"],
 
-    // Uncomment the following to remove healthd from the build.
-    // overrides: [
-    //     "healthd",
-    // ],
+    overrides: [
+        "healthd",
+    ],
 }
 
-    3.1 (recommended) To remove healthd from the build, keep "overrides"
-          section, and include the following in device.mk:
-            DEVICE_FRAMEWORK_MANIFEST_FILE += \
-                system/libhidl/vintfdata/manifest_healthd_exclude.xml
+    3.1 (recommended) To remove healthd from the build, keep "overrides" section.
     3.2 To keep healthd in the build, remove "overrides" section.
 
 4. Create device/<manufacturer>/<device>/health/android.hardware.health@2.0-service.<device>.rc
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
index 34a96a0..88a9e26 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
@@ -470,7 +470,7 @@
     status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
                                   OMX_StateExecuting);
     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
-    status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+    status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT);
     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
     ASSERT_EQ(msg.type, Message::Type::EVENT);
     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
index c1863d5..1575ba2 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -41,6 +41,8 @@
 /* As component is switching states (loaded<->idle<->execute), dequeueMessage()
  * expects the events to be received within this duration */
 #define DEFAULT_TIMEOUT 100000
+// b/70933963
+#define RELAXED_TIMEOUT 400000
 /* Time interval between successive Input/Output enqueues */
 #define DEFAULT_TIMEOUT_Q 2000
 /* While the component is amidst a process call, asynchronous commands like
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 7750a12..4ddc833 100644
--- a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
+++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
@@ -1149,15 +1149,13 @@
             ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
 
             // do not enable the port until all the buffers are supplied
-            status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
-                                              &pBuffer[0], &pBuffer[1]);
+            status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT, &pBuffer[0], &pBuffer[1]);
             ASSERT_EQ(status,
                       android::hardware::media::omx::V1_0::Status::TIMED_OUT);
 
             ASSERT_NO_FATAL_FAILURE(allocatePortBuffers(
                 omxNode, &pBuffer[i - portBase], i, portMode[i - portBase]));
-            status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
-                                              &pBuffer[0], &pBuffer[1]);
+            status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT, &pBuffer[0], &pBuffer[1]);
             ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
             ASSERT_EQ(msg.type, Message::Type::EVENT);
             ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
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;
         }