Merge "Camera: Timing requirement between notify and processCaptureResult"
diff --git a/automotive/can/1.0/Android.bp b/automotive/can/1.0/Android.bp
new file mode 100644
index 0000000..fe2a2be
--- /dev/null
+++ b/automotive/can/1.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.can@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICanBus.hal",
+        "ICanController.hal",
+        "ICanMessageListener.hal",
+        "ICloseHandle.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/automotive/can/1.0/ICanBus.hal b/automotive/can/1.0/ICanBus.hal
new file mode 100644
index 0000000..6ed89f3
--- /dev/null
+++ b/automotive/can/1.0/ICanBus.hal
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+import ICanMessageListener;
+import ICloseHandle;
+
+/**
+ * Represents a CAN bus interface that's up and configured.
+ *
+ * Configuration part is done in ICanController.
+ */
+interface ICanBus {
+    /**
+     * Send CAN message.
+     *
+     * @param message CAN message to send out
+     * @return result OK in the case of success
+     *                PAYLOAD_TOO_LONG if the payload is too long
+     *                INTERFACE_DOWN if the bus is down
+     *                TRANSMISSION_FAILURE in case of transmission failure
+     */
+    send(CanMessage message) generates (Result result);
+
+    /**
+     * Requests HAL implementation to listen for specific CAN messages.
+     *
+     * HAL is responsible for maintaining listener set and sending out messages
+     * to each listener that matches given filter against received message.
+     *
+     * Empty filter list means no filtering. If two or more listeners requested
+     * different filters, HAL server must merge these to fulfill the superset of
+     * these filters. HAL must not send out a message to a listener which filter
+     * doesn't match given message id.
+     *
+     * If filtering is not supported at the hardware level (what's strongly
+     * recommended), it must be covered in the HAL.
+     *
+     * @param filter The set of requested filters
+     * @param listener The interface to receive the messages on
+     * @return result OK in the case of success
+     *                INTERFACE_DOWN if the bus is down
+     * @return close A handle to call in order to remove the listener
+     */
+    listen(vec<CanMessageFilter> filter, ICanMessageListener listener)
+            generates (Result result, ICloseHandle close);
+};
diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal
new file mode 100644
index 0000000..2c7494a
--- /dev/null
+++ b/automotive/can/1.0/ICanController.hal
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * Represents a CAN controller that's capable of configuring CAN bus interfaces.
+ *
+ * The goal of this service is to configure CAN interfaces and bring up HIDL
+ * server instances of ICanBus for each one that's up.
+ *
+ * Providing an ICanController interface to configure CAN buses is optional.
+ * A system can elect to publish only ICanBus if the hardware is hardcoded
+ * for a specific application.
+ */
+interface ICanController {
+    /**
+     * Type of an interface, a mean to express the domain of device address.
+     */
+    enum InterfaceType : uint8_t {
+        /**
+         * Virtual SocketCAN interface.
+         *
+         * The address is an interface name, such as vcan0. If the interface
+         * doesn't exist, HAL server must create it.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - address.
+         */
+        VIRTUAL,
+
+        /**
+         * Native SocketCAN interface.
+         *
+         * The address is an interface name, such as can0.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - address;
+         *  - serialno.
+         */
+        SOCKETCAN,
+
+        /**
+         * Serial-based interface.
+         *
+         * The address is a patch to a device, such as /dev/ttyUSB0.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - address;
+         *  - serialno.
+         */
+        SLCAN,
+
+        /**
+         * Proprietary interface, specific to the hardware system Android
+         * is running on. Instead of using address field, the interface is
+         * addressed with 0-based index.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - index
+         */
+        INDEXED
+    };
+
+    enum Result : uint8_t {
+        OK,
+
+        /**
+         * General error class, if others are not applicable.
+         */
+        UNKNOWN_ERROR,
+
+        /**
+         * Up request was called out of order (i.e. trying to up the
+         * interface twice).
+         */
+        INVALID_STATE,
+
+        /** Interface type is not supported. */
+        NOT_SUPPORTED,
+
+        /**
+         * Provided address (interface name, device path) doesn't exist or there
+         * is no device with a given serial no.
+         */
+        BAD_ADDRESS,
+
+        /** Provided baud rate is not supported by the hardware. */
+        BAD_BAUDRATE,
+    };
+
+    /**
+     * Configuration of the (physical or virtual) CAN bus.
+     *
+     * ISO TP and CAN FD are currently not supported.
+     */
+    struct BusConfiguration {
+        /**
+         * Name under which ICanBus HIDL service should be published.
+         *
+         * It must consist of only alphanumeric characters and underscore
+         * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long.
+         */
+        string name;
+
+        /**
+         * Type of the hardware (or virtual) CAN interface.
+         */
+        InterfaceType iftype;
+
+        /**
+         * Identification of hardware interface to configure.
+         */
+        safe_union InterfaceIdentifier {
+            /**
+             * Interface name or other mean of identification of the specific
+             * interface port. Syntax depends on {@see iftype}, for details
+             * {@see InterfaceType}.
+             */
+            string address;
+
+            /**
+             * Numerical identifier of interface, used for InterfaceType#INDEXED.
+             */
+            uint8_t index;
+
+            /**
+             * Alternatively to providing {@see address}, one may provide a list
+             * of interface serial number suffixes. If there happens to be
+             * a device (like USB2CAN) with a matching serial number suffix,
+             * it gets selected.
+             *
+             * Client may utilize this in two ways: by matching against the
+             * entire serial number, or the last few characters (usually one).
+             * The former is better for small-scale test deployments (with just
+             * a handful of vehicles), the latter is good for larger scale
+             * (where a small suffix list may support large test fleet).
+             */
+            vec<string> serialno;
+        } interfaceId;
+
+        /**
+         * Baud rate for CAN communication.
+         *
+         * Typical baud rates are: 100000, 125000, 250000, 500000.
+         *
+         * For virtual interfaces this value is ignored.
+         */
+        uint32_t baudrate;
+    };
+
+    /**
+     * Fetches the list of interface types supported by this HAL server.
+     *
+     * @return iftypes The list of supported interface types
+     */
+    getSupportedInterfaceTypes() generates (vec<InterfaceType> iftypes);
+
+    /**
+     * Bring up the CAN interface and publish ICanBus server instance.
+     *
+     * @param config Configuration of the CAN interface
+     * @return result OK if the operation succeeded; error code otherwise.
+     */
+    upInterface(BusConfiguration config) generates (Result result);
+
+    /**
+     * Unpublish ICanBus server instance and bring down the CAN interface.
+     *
+     * In case of failure, at least the ICanBus server instance must be
+     * unpublished and resources freed on best-effort basis.
+     *
+     * @param name Name of the interface (@see BusConfiguration#name} to
+     * bring down
+     * @return success true in case of success, false otherwise
+     */
+    downInterface(string name) generates (bool success);
+};
diff --git a/automotive/can/1.0/ICanMessageListener.hal b/automotive/can/1.0/ICanMessageListener.hal
new file mode 100644
index 0000000..992d1c7
--- /dev/null
+++ b/automotive/can/1.0/ICanMessageListener.hal
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * CAN message listener.
+ */
+interface ICanMessageListener {
+    /**
+     * Called on received CAN message.
+     *
+     * The timestamp field of message struct is set to time when the message
+     * was received by the hardware. If it's not possible to fetch exact
+     * hardware time, this field should be set as early as possible to decrease
+     * potential time delta.
+     *
+     * @param message Received CAN message
+     */
+    onReceive(CanMessage message);
+
+    /**
+     * Called on error event.
+     *
+     * @param error Error type
+     */
+    onError(ErrorEvent error);
+};
diff --git a/automotive/can/1.0/ICloseHandle.hal b/automotive/can/1.0/ICloseHandle.hal
new file mode 100644
index 0000000..924c58b
--- /dev/null
+++ b/automotive/can/1.0/ICloseHandle.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ *
+ * When close() is called OR when the interface is released, the underlying
+ * resources must be freed.
+ */
+interface ICloseHandle {
+    /**
+     * Closes the handle.
+     *
+     * The call must not fail and must be issued by the client at most once.
+     * Otherwise, the server must ignore subsequent calls.
+     */
+    close();
+};
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
new file mode 100644
index 0000000..0a4afd6
--- /dev/null
+++ b/automotive/can/1.0/default/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "android.hardware.automotive.can@defaults",
+    cpp_std: "experimental",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
+    ],
+    shared_libs: [
+        "libbase",
+        "libutils",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.automotive.can@1.0-service",
+    init_rc: ["android.hardware.automotive.can@1.0-service.rc"],
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "CanBus.cpp",
+        "CanBusNative.cpp",
+        "CanBusVirtual.cpp",
+        "CanController.cpp",
+        "CanSocket.cpp",
+        "CloseHandle.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+        "libhidltransport",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libnetdevice",
+    ],
+}
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
new file mode 100644
index 0000000..65da291
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBus.h"
+
+#include "CloseHandle.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+#include <linux/can.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Whether to log sent/received packets.
+ */
+static constexpr bool kSuperVerbose = false;
+
+Return<Result> CanBus::send(const CanMessage& message) {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+    if (!mIsUp) return Result::INTERFACE_DOWN;
+
+    if (UNLIKELY(kSuperVerbose)) {
+        LOG(VERBOSE) << "Sending " << toString(message);
+    }
+
+    if (message.payload.size() > CAN_MAX_DLEN) return Result::PAYLOAD_TOO_LONG;
+
+    struct canfd_frame frame = {};
+    frame.can_id = message.id;
+    frame.len = message.payload.size();
+    memcpy(frame.data, message.payload.data(), message.payload.size());
+
+    if (!mSocket->send(frame)) return Result::TRANSMISSION_FAILURE;
+
+    return Result::OK;
+}
+
+Return<void> CanBus::listen(const hidl_vec<CanMessageFilter>& filter,
+                            const sp<ICanMessageListener>& listenerCb, listen_cb _hidl_cb) {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (listenerCb == nullptr) {
+        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+        return {};
+    }
+    if (!mIsUp) {
+        _hidl_cb(Result::INTERFACE_DOWN, nullptr);
+        return {};
+    }
+
+    std::lock_guard<std::mutex> lckListeners(mListenersGuard);
+
+    sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
+        std::lock_guard<std::mutex> lck(mListenersGuard);
+        std::erase_if(mListeners, [&](const auto& e) { return e.callback == listenerCb; });
+    });
+    mListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
+    auto& listener = mListeners.back();
+
+    // fix message IDs to have all zeros on bits not covered by mask
+    std::for_each(listener.filter.begin(), listener.filter.end(),
+                  [](auto& rule) { rule.id &= rule.mask; });
+
+    _hidl_cb(Result::OK, closeHandle);
+    return {};
+}
+
+CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
+
+CanBus::~CanBus() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+    CHECK(!mIsUp) << "Interface is still up while being destroyed";
+
+    std::lock_guard<std::mutex> lckListeners(mListenersGuard);
+    CHECK(mListeners.empty()) << "Listeners list is not empty while interface is being destroyed";
+}
+
+ICanController::Result CanBus::preUp() {
+    return ICanController::Result::OK;
+}
+
+bool CanBus::postDown() {
+    return true;
+}
+
+ICanController::Result CanBus::up() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (mIsUp) {
+        LOG(WARNING) << "Interface is already up";
+        return ICanController::Result::INVALID_STATE;
+    }
+
+    const auto preResult = preUp();
+    if (preResult != ICanController::Result::OK) return preResult;
+
+    const auto isUp = netdevice::isUp(mIfname);
+    if (!isUp.has_value()) {
+        // preUp() should prepare the interface (either create or make sure it's there)
+        LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
+        return ICanController::Result::BAD_ADDRESS;
+    }
+    mWasUpInitially = *isUp;
+
+    if (!mWasUpInitially && !netdevice::up(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " up";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    using namespace std::placeholders;
+    CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
+    CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this);
+    mSocket = CanSocket::open(mIfname, rdcb, errcb);
+    if (!mSocket) {
+        if (!mWasUpInitially) netdevice::down(mIfname);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    mIsUp = true;
+    return ICanController::Result::OK;
+}
+
+void CanBus::clearListeners() {
+    std::vector<wp<ICloseHandle>> listenersToClose;
+    {
+        std::lock_guard<std::mutex> lck(mListenersGuard);
+        std::transform(mListeners.begin(), mListeners.end(), std::back_inserter(listenersToClose),
+                       [](const auto& e) { return e.closeHandle; });
+    }
+
+    for (auto& weakListener : listenersToClose) {
+        /* Between populating listenersToClose and calling close method here, some listeners might
+         * have been already removed from the original mListeners list (resulting in a dangling weak
+         * pointer here). It's fine - we just want to clean them up. */
+        auto listener = weakListener.promote();
+        if (listener != nullptr) listener->close();
+    }
+
+    std::lock_guard<std::mutex> lck(mListenersGuard);
+    CHECK(mListeners.empty()) << "Listeners list wasn't emptied";
+}
+
+bool CanBus::down() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (!mIsUp) {
+        LOG(WARNING) << "Interface is already down";
+        return false;
+    }
+    mIsUp = false;
+
+    clearListeners();
+    mSocket.reset();
+
+    bool success = true;
+
+    if (!mWasUpInitially && !netdevice::down(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " down";
+        // don't return yet, let's try to do best-effort cleanup
+        success = false;
+    }
+
+    if (!postDown()) success = false;
+
+    return success;
+}
+
+/**
+ * Match the filter set against message id.
+ *
+ * For details on the filters syntax, please see CanMessageFilter at
+ * the HAL definition (types.hal).
+ *
+ * \param filter Filter to match against
+ * \param id Message id to filter
+ * \return true if the message id matches the filter, false otherwise
+ */
+static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) {
+    if (filter.size() == 0) return true;
+
+    bool anyNonInvertedPresent = false;
+    bool anyNonInvertedSatisfied = false;
+    for (auto& rule : filter) {
+        const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted;
+        if (rule.inverted) {
+            // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
+            if (!satisfied) return false;
+        } else {
+            anyNonInvertedPresent = true;
+            if (satisfied) anyNonInvertedSatisfied = true;
+        }
+    }
+    return !anyNonInvertedPresent || anyNonInvertedSatisfied;
+}
+
+void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
+    CanMessage message = {};
+    message.id = frame.can_id;
+    message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
+    message.timestamp = timestamp.count();
+
+    if (UNLIKELY(kSuperVerbose)) {
+        LOG(VERBOSE) << "Got message " << toString(message);
+    }
+
+    std::lock_guard<std::mutex> lck(mListenersGuard);
+    for (auto& listener : mListeners) {
+        if (!match(listener.filter, message.id)) continue;
+        if (!listener.callback->onReceive(message).isOk()) {
+            LOG(WARNING) << "Failed to notify listener about message";
+        }
+    }
+}
+
+void CanBus::onError() {
+    std::lock_guard<std::mutex> lck(mListenersGuard);
+    for (auto& listener : mListeners) {
+        if (!listener.callback->onError(ErrorEvent::HARDWARE_ERROR).isOk()) {
+            LOG(WARNING) << "Failed to notify listener about error";
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
new file mode 100644
index 0000000..81a83c8
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "CanSocket.h"
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <utils/Mutex.h>
+
+#include <atomic>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanBus : public ICanBus {
+    virtual ~CanBus();
+
+    Return<Result> send(const CanMessage& message) override;
+    Return<void> listen(const hidl_vec<CanMessageFilter>& filter,
+                        const sp<ICanMessageListener>& listener, listen_cb _hidl_cb) override;
+
+    ICanController::Result up();
+    bool down();
+
+  protected:
+    CanBus(const std::string& ifname);
+
+    /**
+     * Prepare the SocketCAN interface.
+     *
+     * After calling this method, mIfname network interface is available and ready to be brought up.
+     */
+    virtual ICanController::Result preUp();
+
+    /**
+     * Cleanup after bringing the interface down.
+     *
+     * This is a counterpart to preUp().
+     */
+    virtual bool postDown();
+
+    /** Network interface name. */
+    const std::string mIfname;
+
+  private:
+    struct CanMessageListener {
+        sp<ICanMessageListener> callback;
+        hidl_vec<CanMessageFilter> filter;
+        wp<ICloseHandle> closeHandle;
+    };
+    void clearListeners();
+
+    void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp);
+    void onError();
+
+    std::mutex mListenersGuard;
+    std::vector<CanMessageListener> mListeners GUARDED_BY(mListenersGuard);
+
+    std::unique_ptr<CanSocket> mSocket;
+    bool mWasUpInitially;
+
+    /**
+     * Guard for up flag is required to be held for entire time when the interface is being used
+     * (i.e. message being sent), because we don't want the interface to be torn down while
+     * executing that operation.
+     */
+    std::mutex mIsUpGuard;
+    bool mIsUp GUARDED_BY(mIsUpGuard) = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp
new file mode 100644
index 0000000..365b749
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusNative.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusNative.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+CanBusNative::CanBusNative(const std::string& ifname, uint32_t baudrate)
+    : CanBus(ifname), mBaudrate(baudrate) {}
+
+ICanController::Result CanBusNative::preUp() {
+    if (!netdevice::exists(mIfname)) {
+        LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
+        return ICanController::Result::BAD_ADDRESS;
+    }
+
+    if (!netdevice::down(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    if (!netdevice::can::setBitrate(mIfname, mBaudrate)) {
+        LOG(ERROR) << "Can't set bitrate " << mBaudrate << " for " << mIfname;
+        return ICanController::Result::BAD_BAUDRATE;
+    }
+
+    return ICanController::Result::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusNative.h b/automotive/can/1.0/default/CanBusNative.h
new file mode 100644
index 0000000..126f1cb
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusNative.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanBusNative : public CanBus {
+    CanBusNative(const std::string& ifname, uint32_t baudrate);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+
+  private:
+    const uint32_t mBaudrate;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusVirtual.cpp b/automotive/can/1.0/default/CanBusVirtual.cpp
new file mode 100644
index 0000000..cc59fa9
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusVirtual.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
+
+ICanController::Result CanBusVirtual::preUp() {
+    if (netdevice::exists(mIfname)) return ICanController::Result::OK;
+
+    LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating...";
+    mWasCreated = true;
+    if (!netdevice::add(mIfname, "vcan")) {
+        LOG(ERROR) << "Can't create vcan interface " << mIfname;
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    return ICanController::Result::OK;
+}
+
+bool CanBusVirtual::postDown() {
+    if (mWasCreated) {
+        mWasCreated = false;
+        if (!netdevice::del(mIfname)) {
+            LOG(ERROR) << "Couldn't remove vcan interface " << mIfname;
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusVirtual.h b/automotive/can/1.0/default/CanBusVirtual.h
new file mode 100644
index 0000000..c2d5794
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusVirtual.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanBusVirtual : public CanBus {
+    CanBusVirtual(const std::string& ifname);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    bool mWasCreated = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
new file mode 100644
index 0000000..20adbe1
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include "CanBusNative.h"
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <regex>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
+
+Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
+    _hidl_cb({
+            ICanController::InterfaceType::VIRTUAL,
+            ICanController::InterfaceType::SOCKETCAN,
+    });
+    return {};
+}
+
+static bool isValidName(const std::string& name) {
+    static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
+    return std::regex_match(name, nameRE);
+}
+
+Return<ICanController::Result> CanController::upInterface(
+        const ICanController::BusConfiguration& config) {
+    LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config);
+
+    std::lock_guard<std::mutex> lck(mCanBusesGuard);
+
+    if (!isValidName(config.name)) {
+        LOG(ERROR) << "Bus name " << config.name << " is invalid";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    if (mCanBuses.find(config.name) != mCanBuses.end()) {
+        LOG(ERROR) << "Bus " << config.name << " is already up";
+        return ICanController::Result::INVALID_STATE;
+    }
+
+    sp<CanBus> busService;
+
+    if (config.iftype == ICanController::InterfaceType::SOCKETCAN) {
+        // TODO(b/135918744): support serialno
+        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+            busService = new CanBusNative(config.interfaceId.address(), config.baudrate);
+        } else {
+            return ICanController::Result::BAD_ADDRESS;
+        }
+    } else if (config.iftype == ICanController::InterfaceType::VIRTUAL) {
+        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+            busService = new CanBusVirtual(config.interfaceId.address());
+        } else {
+            return ICanController::Result::BAD_ADDRESS;
+        }
+    } else {
+        return ICanController::Result::NOT_SUPPORTED;
+    }
+
+    const auto result = busService->up();
+    if (result != ICanController::Result::OK) return result;
+
+    if (busService->registerAsService(config.name) != OK) {
+        LOG(ERROR) << "Failed to register ICanBus/" << config.name;
+        if (!busService->down()) {
+            LOG(WARNING) << "Failed to bring down CAN bus that failed to register";
+        }
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    mCanBuses[config.name] = busService;
+
+    return ICanController::Result::OK;
+}
+
+Return<bool> CanController::downInterface(const hidl_string& name) {
+    LOG(VERBOSE) << "Attempting to bring interface down: " << name;
+
+    std::lock_guard<std::mutex> lck(mCanBusesGuard);
+
+    auto busEntry = mCanBuses.extract(name);
+    if (!busEntry) {
+        LOG(WARNING) << "Interface " << name << " is not up";
+        return false;
+    }
+
+    auto success = true;
+
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    if (!manager || !manager->tryUnregister(ICanBus::descriptor, name, busEntry.mapped())) {
+        LOG(ERROR) << "Couldn't unregister " << name;
+        // don't return yet, let's try to do best-effort cleanup
+        success = false;
+    }
+
+    if (!busEntry.mapped()->down()) {
+        LOG(ERROR) << "Couldn't bring " << name << " down";
+        success = false;
+    }
+
+    return success;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h
new file mode 100644
index 0000000..0674d0e
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanController : public ICanController {
+    Return<void> getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override;
+
+    Return<ICanController::Result> upInterface(
+            const ICanController::BusConfiguration& config) override;
+    Return<bool> downInterface(const hidl_string& name) override;
+
+  private:
+    std::mutex mCanBusesGuard;
+    std::map<std::string, sp<CanBus>> mCanBuses GUARDED_BY(mCanBusesGuard);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
new file mode 100644
index 0000000..4d86de6
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanSocket.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+#include <linux/can.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+using namespace std::chrono_literals;
+
+/**
+ * How frequently the read thread checks whether the interface was asked to be down.
+ *
+ * Note: This does *not* affect read timing or bandwidth, just CPU load vs time to
+ *       down the interface.
+ */
+static constexpr auto kReadPooling = 100ms;
+
+std::unique_ptr<CanSocket> CanSocket::open(const std::string& ifname, ReadCallback rdcb,
+                                           ErrorCallback errcb) {
+    auto sock = netdevice::can::socket(ifname);
+    if (!sock.ok()) {
+        LOG(ERROR) << "Can't open CAN socket on " << ifname;
+        return nullptr;
+    }
+
+    // Can't use std::make_unique due to private CanSocket constructor.
+    return std::unique_ptr<CanSocket>(new CanSocket(std::move(sock), rdcb, errcb));
+}
+
+CanSocket::CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb)
+    : mReadCallback(rdcb),
+      mErrorCallback(errcb),
+      mSocket(std::move(socket)),
+      mReaderThread(&CanSocket::readerThread, this) {}
+
+CanSocket::~CanSocket() {
+    mStopReaderThread = true;
+    mReaderThread.join();
+}
+
+bool CanSocket::send(const struct canfd_frame& frame) {
+    const auto res = write(mSocket.get(), &frame, CAN_MTU);
+    if (res < 0) {
+        LOG(DEBUG) << "CanSocket send failed: " << errno;
+        return false;
+    }
+    if (res != CAN_MTU) {
+        LOG(DEBUG) << "CanSocket sent wrong number of bytes: " << res;
+        return false;
+    }
+    return true;
+}
+
+static struct timeval toTimeval(std::chrono::microseconds t) {
+    struct timeval tv;
+    tv.tv_sec = t / 1s;
+    tv.tv_usec = (t % 1s) / 1us;
+    return tv;
+}
+
+static int selectRead(const base::unique_fd& fd, std::chrono::microseconds timeout) {
+    auto timeouttv = toTimeval(timeout);
+    fd_set readfds;
+    FD_ZERO(&readfds);
+    FD_SET(fd.get(), &readfds);
+    return select(fd.get() + 1, &readfds, nullptr, nullptr, &timeouttv);
+}
+
+void CanSocket::readerThread() {
+    LOG(VERBOSE) << "Reader thread started";
+
+    while (!mStopReaderThread) {
+        /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3).
+         * This is unfortunately not supported for SocketCAN, so we need to rely on select(3).
+         */
+        const auto sel = selectRead(mSocket, kReadPooling);
+        if (sel == 0) continue;  // timeout
+        if (sel == -1) {
+            LOG(ERROR) << "Select failed: " << errno;
+            break;
+        }
+
+        struct canfd_frame frame;
+        const auto nbytes = read(mSocket.get(), &frame, CAN_MTU);
+
+        /* We could use SIOCGSTAMP to get a precise UNIX timestamp for a given packet, but what
+         * we really need is a time since boot. There is no direct way to convert between these
+         * clocks. We could implement a class to calculate the difference between the clocks
+         * (querying both several times and picking the smallest difference); apply the difference
+         * to a SIOCGSTAMP returned value; re-synchronize if the elapsed time is too much in the
+         * past (indicating the UNIX timestamp might have been adjusted).
+         *
+         * Apart from the added complexity, it's possible the added calculations and system calls
+         * would add so much time to the processing pipeline so the precision of the reported time
+         * was buried under the subsystem latency. Let's just use a local time since boot here and
+         * leave precise hardware timestamps for custom proprietary implementations (if needed).
+         */
+        const std::chrono::nanoseconds ts(elapsedRealtimeNano());
+
+        if (nbytes != CAN_MTU) {
+            if (nbytes >= 0) {
+                LOG(ERROR) << "Failed to read CAN packet, got " << nbytes << " bytes";
+                break;
+            }
+            if (errno == EAGAIN) continue;
+
+            LOG(ERROR) << "Failed to read CAN packet: " << errno;
+            break;
+        }
+
+        mReadCallback(frame, ts);
+    }
+
+    if (!mStopReaderThread) mErrorCallback();
+
+    LOG(VERBOSE) << "Reader thread stopped";
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
new file mode 100644
index 0000000..cd7162d
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <linux/can.h>
+
+#include <atomic>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Wrapper around SocketCAN socket.
+ */
+struct CanSocket {
+    using ReadCallback = std::function<void(const struct canfd_frame&, std::chrono::nanoseconds)>;
+    using ErrorCallback = std::function<void()>;
+
+    /**
+     * Open and bind SocketCAN socket.
+     *
+     * \param ifname SocketCAN network interface name (such as can0)
+     * \param rdcb Callback on received messages
+     * \param errcb Callback on socket failure
+     * \return Socket instance, or nullptr if it wasn't possible to open one
+     */
+    static std::unique_ptr<CanSocket> open(const std::string& ifname, ReadCallback rdcb,
+                                           ErrorCallback errcb);
+    virtual ~CanSocket();
+
+    /**
+     * Send CAN frame.
+     *
+     * \param frame Frame to send
+     * \return true in case of success, false otherwise
+     */
+    bool send(const struct canfd_frame& frame);
+
+  private:
+    CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb);
+    void readerThread();
+
+    ReadCallback mReadCallback;
+    ErrorCallback mErrorCallback;
+
+    const base::unique_fd mSocket;
+    std::thread mReaderThread;
+    std::atomic<bool> mStopReaderThread = false;
+
+    DISALLOW_COPY_AND_ASSIGN(CanSocket);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CloseHandle.cpp b/automotive/can/1.0/default/CloseHandle.cpp
new file mode 100644
index 0000000..13693d2
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CloseHandle.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
+
+CloseHandle::~CloseHandle() {
+    close();
+}
+
+Return<void> CloseHandle::close() {
+    const auto wasClosed = mIsClosed.exchange(true);
+    if (wasClosed) return {};
+
+    mCallback();
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h
new file mode 100644
index 0000000..94972e0
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/can/1.0/ICloseHandle.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Generic ICloseHandle implementation ignoring double-close events.
+ */
+struct CloseHandle : public ICloseHandle {
+    using Callback = std::function<void()>;
+
+    /**
+     * Create a handle with a callback.
+     *
+     * The callback is guaranteed to be called exactly once.
+     *
+     * \param callback Called on the first close() call, or on destruction of the handle
+     */
+    CloseHandle(Callback callback);
+    virtual ~CloseHandle();
+
+    Return<void> close() override;
+
+  private:
+    Callback mCallback;
+    std::atomic<bool> mIsClosed = false;
+
+    DISALLOW_COPY_AND_ASSIGN(CloseHandle);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc
new file mode 100644
index 0000000..a629bda
--- /dev/null
+++ b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc
@@ -0,0 +1,5 @@
+service can-hal-1.0-service /vendor/bin/hw/android.hardware.automotive.can@1.0-service
+    class hal
+    capabilities NET_ADMIN
+    user vehicle_network
+    group system inet
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
new file mode 100644
index 0000000..31e5ad0
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.automotive.can@libnetdevice",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor_available: true,
+    relative_install_path: "hw",
+    srcs: [
+        "NetlinkRequest.cpp",
+        "NetlinkSocket.cpp",
+        "can.cpp",
+        "common.cpp",
+        "libnetdevice.cpp",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
new file mode 100644
index 0000000..9845bc7
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NetlinkRequest.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace netdevice {
+namespace impl {
+
+static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
+    return reinterpret_cast<struct rtattr*>(  //
+            reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
+}
+
+struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
+                         size_t dataLen) {
+    size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
+    if (newLen > maxLen) {
+        LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
+        return nullptr;
+    }
+
+    auto attr = nlmsg_tail(n);
+    attr->rta_len = RTA_SPACE(dataLen);
+    attr->rta_type = type;
+    if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
+
+    n->nlmsg_len = newLen;
+    return attr;
+}
+
+struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) {
+    return addattr_l(n, maxLen, type, nullptr, 0);
+}
+
+void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) {
+    size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
+    nest->rta_len = nestLen;
+}
+
+}  // namespace impl
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
new file mode 100644
index 0000000..21202e3
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <linux/rtnetlink.h>
+
+#include <string>
+
+namespace android {
+namespace netdevice {
+
+typedef unsigned short rtattrtype_t;  // as in rtnetlink.h
+typedef __u16 nlmsgtype_t;            // as in netlink.h
+
+/**
+ * Implementation details, do not use outside NetlinkRequest template.
+ */
+namespace impl {
+
+struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
+                         size_t dataLen);
+struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
+void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
+
+}  // namespace impl
+
+/**
+ * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
+ *
+ * \param T specific message header (such as struct ifinfomsg)
+ * \param BUFSIZE how much space to reserve for payload (not counting the header size)
+ */
+template <class T, unsigned int BUFSIZE = 128>
+struct NetlinkRequest {
+    /**
+     * Create empty message.
+     *
+     * \param type Message type (such as RTM_NEWLINK)
+     * \param flags Message flags (such as NLM_F_REQUEST)
+     */
+    NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
+        mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
+        mRequest.nlmsg.nlmsg_type = type;
+        mRequest.nlmsg.nlmsg_flags = flags;
+    }
+
+    /** Returns pointer to raw netlink message header. */
+    struct nlmsghdr* header() {
+        return &mRequest.nlmsg;
+    }
+    /** Reference to message-specific header. */
+    T& data() { return mRequest.data; }
+
+    /**
+     * Adds an attribute of a simple type.
+     *
+     * If this method fails (i.e. due to insufficient space), the message will be marked
+     * as bad (\see isGood).
+     *
+     * \param type attribute type (such as IFLA_IFNAME)
+     * \param attr attribute data
+     */
+    template <class A>
+    void addattr(rtattrtype_t type, const A& attr) {
+        if (!mIsGood) return;
+        auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
+        if (ap == nullptr) mIsGood = false;
+    }
+
+    template <>
+    void addattr(rtattrtype_t type, const std::string& s) {
+        if (!mIsGood) return;
+        auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
+        if (ap == nullptr) mIsGood = false;
+    }
+
+    /**
+     * Guard class to frame nested attributes. See nest(int).
+     */
+    struct Nest {
+        Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
+        ~Nest() { mReq.nestEnd(mAttr); }
+
+      private:
+        NetlinkRequest& mReq;
+        struct rtattr* mAttr;
+
+        DISALLOW_COPY_AND_ASSIGN(Nest);
+    };
+
+    /**
+     * Add nested attribute.
+     *
+     * The returned object is a guard for auto-nesting children inside the argument attribute.
+     * When the Nest object goes out of scope, the nesting attribute is closed.
+     *
+     * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
+     * inside IFLA_LINKINFO:
+     *    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+     *    {
+     *        auto linkinfo = req.nest(IFLA_LINKINFO);
+     *        req.addattr(IFLA_INFO_KIND, "can");
+     *        {
+     *            auto infodata = req.nest(IFLA_INFO_DATA);
+     *            req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
+     *        }
+     *    }
+     *    // use req
+     *
+     * \param type attribute type (such as IFLA_LINKINFO)
+     */
+    Nest nest(int type) { return Nest(*this, type); }
+
+    /**
+     * Indicates, whether the message is in a good state.
+     *
+     * The bad state is usually a result of payload buffer being too small.
+     * You can modify BUFSIZE template parameter to fix this.
+     */
+    bool isGood() const { return mIsGood; }
+
+  private:
+    bool mIsGood = true;
+
+    struct {
+        struct nlmsghdr nlmsg;
+        T data;
+        char buf[BUFSIZE];
+    } mRequest = {};
+
+    struct rtattr* nestStart(rtattrtype_t type) {
+        if (!mIsGood) return nullptr;
+        auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
+        if (attr == nullptr) mIsGood = false;
+        return attr;
+    }
+
+    void nestEnd(struct rtattr* nest) {
+        if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
+    }
+};
+
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
new file mode 100644
index 0000000..0514764
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NetlinkSocket.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace netdevice {
+
+NetlinkSocket::NetlinkSocket(int protocol) {
+    mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
+    if (!mFd.ok()) {
+        LOG(ERROR) << "Can't open Netlink socket: " << errno;
+        mFailed = true;
+        return;
+    }
+
+    struct sockaddr_nl sa = {};
+    sa.nl_family = AF_NETLINK;
+
+    if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
+        LOG(ERROR) << "Can't bind Netlink socket: " << errno;
+        mFd.reset();
+        mFailed = true;
+    }
+}
+
+bool NetlinkSocket::send(struct nlmsghdr* nlmsg) {
+    if (mFailed) return false;
+
+    nlmsg->nlmsg_pid = 0;  // kernel
+    nlmsg->nlmsg_seq = mSeq++;
+    nlmsg->nlmsg_flags |= NLM_F_ACK;
+
+    struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
+
+    struct sockaddr_nl sa = {};
+    sa.nl_family = AF_NETLINK;
+
+    struct msghdr msg = {};
+    msg.msg_name = &sa;
+    msg.msg_namelen = sizeof(sa);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    if (sendmsg(mFd.get(), &msg, 0) < 0) {
+        LOG(ERROR) << "Can't send Netlink message: " << errno;
+        return false;
+    }
+    return true;
+}
+
+bool NetlinkSocket::receiveAck() {
+    if (mFailed) return false;
+
+    char buf[8192];
+
+    struct sockaddr_nl sa;
+    struct iovec iov = {buf, sizeof(buf)};
+
+    struct msghdr msg = {};
+    msg.msg_name = &sa;
+    msg.msg_namelen = sizeof(sa);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    const ssize_t status = recvmsg(mFd.get(), &msg, 0);
+    if (status < 0) {
+        LOG(ERROR) << "Failed to receive Netlink message: " << errno;
+        return false;
+    }
+    size_t remainingLen = status;
+
+    if (msg.msg_flags & MSG_TRUNC) {
+        LOG(ERROR) << "Failed to receive Netlink message: truncated";
+        return false;
+    }
+
+    for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
+         nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
+        // We're looking for error/ack message only, ignoring others.
+        if (nlmsg->nlmsg_type != NLMSG_ERROR) {
+            LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
+            continue;
+        }
+
+        // Found error/ack message, return status.
+        auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
+        if (nlerr->error != 0) {
+            LOG(ERROR) << "Received Netlink error message: " << nlerr->error;
+            return false;
+        }
+        return true;
+    }
+    // Couldn't find any error/ack messages.
+    return false;
+}
+
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
new file mode 100644
index 0000000..81d6224
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "NetlinkRequest.h"
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+
+#include <linux/netlink.h>
+
+namespace android {
+namespace netdevice {
+
+/**
+ * A wrapper around AF_NETLINK sockets.
+ *
+ * This class is not thread safe to use a single instance between multiple threads, but it's fine to
+ * use multiple instances over multiple threads.
+ */
+struct NetlinkSocket {
+    NetlinkSocket(int protocol);
+
+    /**
+     * Send Netlink message to Kernel.
+     *
+     * @param msg Message to send, nlmsg_seq will be set to next sequence number
+     * @return true, if succeeded
+     */
+    template <class T, unsigned int BUFSIZE>
+    bool send(NetlinkRequest<T, BUFSIZE>& req) {
+        if (!req.isGood()) return false;
+        return send(req.header());
+    }
+
+    /**
+     * Receive Netlink ACK message from Kernel.
+     *
+     * @return true if received ACK message, false in case of error
+     */
+    bool receiveAck();
+
+  private:
+    uint32_t mSeq = 0;
+    base::unique_fd mFd;
+    bool mFailed = false;
+
+    bool send(struct nlmsghdr* msg);
+
+    DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
+};
+
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
new file mode 100644
index 0000000..87617dd
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnetdevice/libnetdevice.h>
+
+#include "NetlinkRequest.h"
+#include "NetlinkSocket.h"
+#include "common.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include <linux/can.h>
+#include <linux/can/netlink.h>
+
+namespace android {
+namespace netdevice {
+namespace can {
+
+base::unique_fd socket(const std::string& ifname) {
+    struct sockaddr_can addr = {};
+    addr.can_family = AF_CAN;
+    addr.can_ifindex = nametoindex(ifname);
+    if (addr.can_ifindex == 0) {
+        LOG(ERROR) << "Interface " << ifname << " doesn't exists";
+        return {};
+    }
+
+    base::unique_fd sock(::socket(PF_CAN, SOCK_RAW, CAN_RAW));
+    if (!sock.ok()) {
+        LOG(ERROR) << "Failed to create CAN socket";
+        return {};
+    }
+
+    if (0 != fcntl(sock.get(), F_SETFL, O_RDWR | O_NONBLOCK)) {
+        LOG(ERROR) << "Couldn't put CAN socket in non-blocking mode";
+        return {};
+    }
+
+    if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
+        LOG(ERROR) << "Can't bind to CAN interface " << ifname;
+        return {};
+    }
+
+    return sock;
+}
+
+bool setBitrate(std::string ifname, uint32_t bitrate) {
+    struct can_bittiming bt = {};
+    bt.bitrate = bitrate;
+
+    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+
+    const auto ifidx = nametoindex(ifname);
+    if (ifidx == 0) {
+        LOG(ERROR) << "Can't find interface " << ifname;
+        return false;
+    }
+    req.data().ifi_index = ifidx;
+
+    {
+        auto linkinfo = req.nest(IFLA_LINKINFO);
+        req.addattr(IFLA_INFO_KIND, "can");
+        {
+            auto infodata = req.nest(IFLA_INFO_DATA);
+            /* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
+             * and IFLA_CAN_CTRLMODE as well. */
+            req.addattr(IFLA_CAN_BITTIMING, bt);
+        }
+    }
+
+    NetlinkSocket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck();
+}
+
+}  // namespace can
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
new file mode 100644
index 0000000..3deac3e
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <net/if.h>
+
+namespace android {
+namespace netdevice {
+
+unsigned int nametoindex(const std::string& ifname) {
+    const auto ifidx = if_nametoindex(ifname.c_str());
+    if (ifidx != 0) return ifidx;
+
+    const auto err = errno;
+    if (err != ENODEV) {
+        LOG(ERROR) << "if_nametoindex(" << ifname << ") failed: " << err;
+    }
+    return 0;
+}
+
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
new file mode 100644
index 0000000..9bdff4d
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace netdevice {
+
+/**
+ * Returns the index of a given network interface.
+ *
+ * If the syscall to check the index fails with other error than ENODEV, it gets logged and the
+ * return value indicates the interface doesn't exists.
+ *
+ * \param ifname Interface to check
+ * \return Interface index, or 0 if the interface doesn't exist
+ */
+unsigned int nametoindex(const std::string& ifname);
+
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
new file mode 100644
index 0000000..ec3f962
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+#include <string>
+
+namespace android {
+namespace netdevice {
+namespace can {
+
+/**
+ * Opens and binds SocketCAN socket.
+ *
+ * @param ifname Interface to open a socket against
+ * @return Socket's FD or -1 in case of failure
+ */
+base::unique_fd socket(const std::string& ifname);
+
+/**
+ * Sets CAN interface bitrate.
+ */
+bool setBitrate(std::string ifname, uint32_t bitrate);
+
+}  // namespace can
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
new file mode 100644
index 0000000..33d5de5
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+namespace android {
+namespace netdevice {
+
+/**
+ * Checks, if the network interface exists.
+ *
+ * @param ifname Interface to check
+ * @return true if it exists, false otherwise
+ */
+bool exists(std::string ifname);
+
+/**
+ * Checks if network interface is up.
+ *
+ * @param ifname Interface to check
+ * @return true/false if the check succeeded, nullopt otherwise
+ */
+std::optional<bool> isUp(std::string ifname);
+
+/**
+ * Brings network interface up.
+ *
+ * @param ifname Interface to bring up
+ * @return true in case of success, false otherwise
+ */
+bool up(std::string ifname);
+
+/**
+ * Brings network interface down.
+ *
+ * @param ifname Interface to bring down
+ * @return true in case of success, false otherwise
+ */
+bool down(std::string ifname);
+
+/**
+ * Adds virtual link.
+ *
+ * @param dev the name of the new virtual device
+ * @param type the type of the new device
+ * @return true in case of success, false otherwise
+ */
+bool add(std::string dev, std::string type);
+
+/**
+ * Deletes virtual link.
+ *
+ * @param dev the name of the device to remove
+ * @return true in case of success, false otherwise
+ */
+bool del(std::string dev);
+
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
new file mode 100644
index 0000000..fc2b193
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnetdevice/libnetdevice.h>
+
+#include "NetlinkRequest.h"
+#include "NetlinkSocket.h"
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <linux/can.h>
+#include <net/if.h>
+
+namespace android {
+namespace netdevice {
+
+bool exists(std::string ifname) {
+    return nametoindex(ifname) != 0;
+}
+
+static bool sendIfreq(unsigned long request, struct ifreq& ifr) {
+    /* For general interfaces it would be socket(AF_INET, SOCK_DGRAM, 0),
+     * but SEPolicy forces us to limit our flexibility here. */
+    base::unique_fd sock(socket(PF_CAN, SOCK_RAW, CAN_RAW));
+    if (!sock.ok()) {
+        LOG(ERROR) << "Can't create socket";
+        return false;
+    }
+
+    if (ioctl(sock.get(), request, &ifr) < 0) {
+        LOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed: " << errno;
+        return false;
+    }
+
+    return true;
+}
+
+static struct ifreq ifreqFromName(const std::string& ifname) {
+    struct ifreq ifr = {};
+    strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
+    return ifr;
+}
+
+std::optional<bool> isUp(std::string ifname) {
+    struct ifreq ifr = ifreqFromName(ifname);
+    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt;
+    return ifr.ifr_flags & IFF_UP;
+}
+
+bool up(std::string ifname) {
+    struct ifreq ifr = ifreqFromName(ifname);
+    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+    ifr.ifr_flags |= IFF_UP;
+    return sendIfreq(SIOCSIFFLAGS, ifr);
+}
+
+bool down(std::string ifname) {
+    struct ifreq ifr = ifreqFromName(ifname);
+    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+    ifr.ifr_flags &= ~IFF_UP;
+    return sendIfreq(SIOCSIFFLAGS, ifr);
+}
+
+bool add(std::string dev, std::string type) {
+    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+    req.addattr(IFLA_IFNAME, dev);
+
+    {
+        auto linkinfo = req.nest(IFLA_LINKINFO);
+        req.addattr(IFLA_INFO_KIND, type);
+    }
+
+    NetlinkSocket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck();
+}
+
+bool del(std::string dev) {
+    NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
+    req.addattr(IFLA_IFNAME, dev);
+
+    NetlinkSocket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck();
+}
+
+}  // namespace netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
new file mode 100644
index 0000000..7ef44fc
--- /dev/null
+++ b/automotive/can/1.0/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+static void canControllerService() {
+    base::SetDefaultTag("CanController");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+    configureRpcThreadpool(16, true);
+    LOG(DEBUG) << "CAN controller service starting...";
+
+    CanController canController;
+    if (canController.registerAsService("socketcan") != OK) {
+        LOG(FATAL) << "Failed to register CAN controller";
+        return;
+    }
+
+    LOG(INFO) << "CAN controller service ready";
+    joinRpcThreadpool();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+int main() {
+    ::android::hardware::automotive::can::V1_0::implementation::canControllerService();
+    return 1;  // canBusService (joinRpcThreadpool) shouldn't exit
+}
diff --git a/automotive/can/1.0/hidl-utils/Android.bp b/automotive/can/1.0/hidl-utils/Android.bp
new file mode 100644
index 0000000..bc8ff13
--- /dev/null
+++ b/automotive/can/1.0/hidl-utils/Android.bp
@@ -0,0 +1,20 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "android.hardware.automotive.can@hidl-utils-lib",
+    export_include_dirs: ["include"],
+}
diff --git a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
new file mode 100644
index 0000000..039f971
--- /dev/null
+++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace hidl_utils {
+
+/**
+ * Helper functor to fetch results from multi-return HIDL calls.
+ * It's meant to be used in place of _hidl_cb callbacks.
+ *
+ * Please note extracting these return variables outside of the callback scope requires making
+ * a copy of each return variable. This may be costly for frequently called HIDL methods with
+ * non-negligible return object size. Please be cautious about performance when using this.
+ *
+ * Example usage:
+ *     Result result;
+ *     sp<ISomeInterface> iface;
+ *     hidlObject->someMethod(arg1, arg2, hidl_utils::fill(&result, &iface)).assertOk();
+ *     // use result and iface
+ */
+template <typename... T>
+struct fill : public std::function<void(const T&...)> {
+    /**
+     * Create _hidl_cb functor that copies the call arguments to specified pointers.
+     *
+     * \param args... Targets to copy the call arguments to
+     */
+    fill(T*... args) : mTargets(args...) {}
+
+    void operator()(const T&... args) { copy<0, T...>(args...); }
+
+  private:
+    std::tuple<T*...> mTargets;
+
+    template <int Pos, typename First>
+    inline void copy(const First& first) {
+        *std::get<Pos>(mTargets) = first;
+    }
+
+    template <int Pos, typename First, typename... Rest>
+    inline void copy(const First& first, const Rest&... rest) {
+        *std::get<Pos>(mTargets) = first;
+        copy<Pos + 1, Rest...>(rest...);
+    }
+};
+
+}  // namespace hidl_utils
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/tools/Android.bp b/automotive/can/1.0/tools/Android.bp
new file mode 100644
index 0000000..8c26985
--- /dev/null
+++ b/automotive/can/1.0/tools/Android.bp
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "canhalctrl",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhalctrl.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+        "libhidltransport",
+    ],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+}
+
+cc_binary {
+    name: "canhaldump",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhaldump.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+        "libhidltransport",
+    ],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+}
+
+cc_binary {
+    name: "canhalsend",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhalsend.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+        "libhidltransport",
+    ],
+}
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
new file mode 100644
index 0000000..fa1048d
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.h>
+
+#include <iostream>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+
+using ICanController = V1_0::ICanController;
+
+static void usage() {
+    std::cerr << "CAN bus HAL Control tool" << std::endl;
+    std::cerr << std::endl << "usage:" << std::endl << std::endl;
+    std::cerr << "canhalctrl up <bus name> <type> <interface> [baudrate]" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus will be published" << std::endl;
+    std::cerr << " type - one of: virtual, socketcan, slcan, indexed" << std::endl;
+    std::cerr << " interface - hardware identifier (like can0, vcan0, /dev/ttyUSB0)" << std::endl;
+    std::cerr << " baudrate - such as 100000, 125000, 250000, 500000" << std::endl;
+    std::cerr << std::endl;
+    std::cerr << "canhalctrl down <bus name>" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus will be published" << std::endl;
+}
+
+static hidl_vec<hidl_string> getControlServices() {
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    hidl_vec<hidl_string> services;
+    manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
+    if (services.size() == 0) {
+        std::cerr << "No ICanController services registered (missing privileges?)" << std::endl;
+        exit(-1);
+    }
+    return services;
+}
+
+static bool isSupported(sp<ICanController> ctrl, ICanController::InterfaceType iftype) {
+    hidl_vec<ICanController::InterfaceType> supported;
+    if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false;
+    return supported.contains(iftype);
+}
+
+static int up(const std::string& busName, ICanController::InterfaceType type,
+              const std::string& interface, uint32_t baudrate) {
+    bool anySupported = false;
+    for (auto&& service : getControlServices()) {
+        auto ctrl = ICanController::getService(service);
+        if (ctrl == nullptr) {
+            std::cerr << "Couldn't open ICanController/" << service;
+            continue;
+        }
+
+        if (!isSupported(ctrl, type)) continue;
+        anySupported = true;
+
+        ICanController::BusConfiguration config = {};
+        config.name = busName;
+        config.iftype = type;
+        config.baudrate = baudrate;
+
+        if (type == ICanController::InterfaceType::INDEXED) {
+            config.interfaceId.index(std::stol(interface));
+        } else {
+            config.interfaceId.address(interface);
+        }
+
+        const auto upresult = ctrl->upInterface(config);
+        if (upresult == ICanController::Result::OK) return 0;
+        std::cerr << "Failed to bring interface up: " << toString(upresult) << std::endl;
+        // Let's continue the loop to try other controllers.
+    }
+
+    if (!anySupported) {
+        std::cerr << "No controller supports " << toString(type) << std::endl;
+    }
+    return -1;
+}
+
+static int down(const std::string& busName) {
+    for (auto&& service : getControlServices()) {
+        auto ctrl = ICanController::getService(service);
+        if (ctrl == nullptr) continue;
+
+        if (ctrl->downInterface(busName)) return 0;
+    }
+
+    std::cerr << "Failed to bring interface " << busName << " down (maybe it's down already?)"
+              << std::endl;
+    return -1;
+}
+
+static std::optional<ICanController::InterfaceType> parseInterfaceType(const std::string& str) {
+    if (str == "virtual") return ICanController::InterfaceType::VIRTUAL;
+    if (str == "socketcan") return ICanController::InterfaceType::SOCKETCAN;
+    if (str == "slcan") return ICanController::InterfaceType::SLCAN;
+    if (str == "indexed") return ICanController::InterfaceType::INDEXED;
+    return std::nullopt;
+}
+
+static int main(int argc, char* argv[]) {
+    base::SetDefaultTag("CanHalControl");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+    if (argc == 0) {
+        usage();
+        return 0;
+    }
+
+    std::string cmd(argv[0]);
+    argv++;
+    argc--;
+
+    if (cmd == "up") {
+        if (argc < 3 || argc > 4) {
+            std::cerr << "Invalid number of arguments to up command: " << argc << std::endl;
+            usage();
+            return -1;
+        }
+
+        const std::string busName(argv[0]);
+        const std::string typeStr(argv[1]);
+        const std::string interface(argv[2]);
+
+        const auto type = parseInterfaceType(typeStr);
+        if (!type) {
+            std::cerr << "Invalid interface type: " << typeStr << std::endl;
+            usage();
+            return -1;
+        }
+
+        long long baudrate = 0;
+        if (argc == 4) {
+            baudrate = std::stoll(argv[3]);
+        }
+
+        return up(busName, *type, interface, baudrate);
+    } else if (cmd == "down") {
+        if (argc != 1) {
+            std::cerr << "Invalid number of arguments to down command: " << argc << std::endl;
+            usage();
+            return -1;
+        }
+
+        return down(argv[0]);
+    } else {
+        std::cerr << "Invalid command: " << cmd << std::endl;
+        usage();
+        return -1;
+    }
+}
+
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char* argv[]) {
+    if (argc < 1) return -1;
+    return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp
new file mode 100644
index 0000000..5713d17
--- /dev/null
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanMessageListener.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.h>
+
+#include <chrono>
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+
+using namespace std::chrono_literals;
+
+using ICanBus = V1_0::ICanBus;
+using Result = V1_0::Result;
+
+struct CanMessageListener : public V1_0::ICanMessageListener {
+    const std::string name;
+
+    CanMessageListener(std::string name) : name(name) {}
+
+    virtual Return<void> onReceive(const V1_0::CanMessage& message) {
+        std::cout << "  " << name << "  " << std::hex << std::uppercase << std::setw(3)
+                  << std::setfill('0') << message.id << std::setw(0);
+        if (message.remoteTransmissionRequest) {
+            std::cout << " RTR";
+        } else {
+            std::cout << "   [" << message.payload.size() << "] ";
+            for (const auto byte : message.payload) {
+                std::cout << " " << unsigned(byte);
+            }
+        }
+        std::cout << std::nouppercase << std::dec << std::endl;
+        return {};
+    }
+
+    virtual Return<void> onError(V1_0::ErrorEvent error) {
+        std::cout << "  " << name << "  " << toString(error) << std::endl;
+        return {};
+    }
+};
+
+static void usage() {
+    std::cerr << "canhaldump - dump CAN bus traffic" << std::endl;
+    std::cerr << std::endl << "usage:" << std::endl << std::endl;
+    std::cerr << "canhaldump <bus name>" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus is be published" << std::endl;
+}
+
+// TODO(b/135918744): extract to a new library
+static sp<ICanBus> tryOpen(const std::string& busname) {
+    auto bus = ICanBus::tryGetService(busname);
+    if (bus != nullptr) return bus;
+
+    /* Fallback for interfaces not registered in manifest. For testing purposes only,
+     * one should not depend on this in production deployment. */
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr);
+    if (ret == nullptr) return nullptr;
+
+    std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, "
+              << "trying to fetch it directly..." << std::endl;
+
+    return ICanBus::castFrom(ret);
+}
+
+static int candump(const std::string& busname) {
+    auto bus = tryOpen(busname);
+    if (bus == nullptr) {
+        std::cerr << "Bus " << busname << " is not available" << std::endl;
+        return -1;
+    }
+
+    Result result;
+    sp<V1_0::ICloseHandle> chnd;
+    // TODO(b/135918744): extract to library
+    bus->listen({}, new CanMessageListener(busname), hidl_utils::fill(&result, &chnd)).assertOk();
+
+    if (result != Result::OK) {
+        std::cerr << "Listen call failed: " << toString(result) << std::endl;
+        return -1;
+    }
+
+    while (true) std::this_thread::sleep_for(1h);
+}
+
+static int main(int argc, char* argv[]) {
+    base::SetDefaultTag("CanHalDump");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+    if (argc == 0) {
+        usage();
+        return 0;
+    }
+
+    if (argc != 1) {
+        std::cerr << "Invalid number of arguments" << std::endl;
+        usage();
+        return -1;
+    }
+
+    return candump(argv[0]);
+}
+
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char* argv[]) {
+    if (argc < 1) return -1;
+    return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp
new file mode 100644
index 0000000..29330c9
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalsend.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <iostream>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+
+using ICanBus = V1_0::ICanBus;
+using Result = V1_0::Result;
+
+static void usage() {
+    std::cerr << "cansend - simple command line tool to send raw CAN frames" << std::endl;
+    std::cerr << std::endl << "usage:" << std::endl << std::endl;
+    std::cerr << "canhalsend <bus name> <can id>#<data>" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus is be published" << std::endl;
+    std::cerr << " can id - such as 1a5" << std::endl;
+    std::cerr << " data - such as deadbeef or 010203" << std::endl;
+}
+
+// TODO(b/135918744): extract to a new library
+static sp<ICanBus> tryOpen(const std::string& busname) {
+    auto bus = ICanBus::tryGetService(busname);
+    if (bus != nullptr) return bus;
+
+    /* Fallback for interfaces not registered in manifest. For testing purposes only,
+     * one should not depend on this in production deployment. */
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr);
+    if (ret == nullptr) return nullptr;
+
+    std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, "
+              << "trying to fetch it directly..." << std::endl;
+
+    return ICanBus::castFrom(ret);
+}
+
+static int cansend(const std::string& busname, V1_0::CanMessageId msgid,
+                   std::vector<uint8_t> payload) {
+    auto bus = tryOpen(busname);
+    if (bus == nullptr) {
+        std::cerr << "Bus " << busname << " is not available" << std::endl;
+        return -1;
+    }
+
+    V1_0::CanMessage msg = {};
+    msg.id = msgid;
+    msg.payload = payload;
+
+    const auto result = bus->send(msg);
+    if (result != Result::OK) {
+        std::cerr << "Send call failed: " << toString(result) << std::endl;
+        return -1;
+    }
+    return 0;
+}
+
+static std::optional<std::tuple<V1_0::CanMessageId, std::vector<uint8_t>>> parseCanMessage(
+        const std::string& msg) {
+    const auto hashpos = msg.find("#");
+    if (hashpos == std::string::npos) return std::nullopt;
+
+    const std::string msgidStr = msg.substr(0, hashpos);
+    const std::string payloadStr = msg.substr(hashpos + 1);
+
+    size_t idx = 0;
+    V1_0::CanMessageId msgid = std::stoi(msgidStr, &idx, 16);
+    if (msgidStr[idx] != '\0') return std::nullopt;
+
+    std::vector<uint8_t> payload;
+    if (payloadStr.size() % 2 != 0) return std::nullopt;
+    for (size_t i = 0; i < payloadStr.size(); i += 2) {
+        std::string byteStr(payloadStr, i, 2);
+        payload.emplace_back(std::stoi(byteStr, &idx, 16));
+        if (byteStr[idx] != '\0') return std::nullopt;
+    }
+
+    return {{msgid, payload}};
+}
+
+static int main(int argc, char* argv[]) {
+    base::SetDefaultTag("CanHalSend");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+    if (argc == 0) {
+        usage();
+        return 0;
+    }
+
+    if (argc != 2) {
+        std::cerr << "Invalid number of arguments" << std::endl;
+        usage();
+        return -1;
+    }
+
+    std::string busname(argv[0]);
+    const auto canmsg = parseCanMessage(argv[1]);
+    if (!canmsg) {
+        std::cerr << "Failed to parse CAN message argument" << std::endl;
+        return -1;
+    }
+    const auto [msgid, payload] = *canmsg;
+
+    return cansend(busname, msgid, payload);
+}
+
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char* argv[]) {
+    if (argc < 1) return -1;
+    return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal
new file mode 100644
index 0000000..37877c6
--- /dev/null
+++ b/automotive/can/1.0/types.hal
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * CAN message ID.
+ *
+ * Does not include any flags like RTR nor ERR, only a plain 11-bit
+ * or 29-bit identifier, as defined in CAN 1.x/2.0x.
+ *
+ * Unused bits must be set to zero.
+ */
+typedef uint32_t CanMessageId;
+
+/**
+ * CAN message being sent or received.
+ */
+struct CanMessage {
+    CanMessageId id;
+
+    /**
+     * CAN message payload, as defined in CAN 1.x and CAN 2.x standards.
+     *
+     * The length of the payload vector directly translates to the length
+     * of the data frame (i.e. includes any padding bytes), so it may be in
+     * a range of:
+     *  - 0-8 bytes for standard CAN;
+     *  - up to 64 bytes for CAN FD.
+     * ISO TP is not supported directly for now.
+     */
+    vec<uint8_t> payload;
+
+    /**
+     * Time in nanoseconds since boot.
+     *
+     * Ignored for outgoing messages.
+     */
+    uint64_t timestamp;
+
+    /**
+     * A request to proactively pull certain data from other ECU in CAN network.
+     *
+     * For details please refer to CAN standard.
+     *
+     * If this flag is set, payload must be empty.
+     */
+    bool remoteTransmissionRequest;
+};
+
+/**
+ * Single filter rule for CAN messages.
+ *
+ * A filter is satisfied if:
+ * ((receivedId & mask) == (id & mask)) == !inverted
+ *
+ * In order for set of filters to match, at least one non-inverted filters must match (if there is
+ * one) and all inverted filters must match. In other words:
+ *  - a single matching non-inverted filter makes the whole set matching;
+ *  - a single non-matching inverted filter makes the whole set non-matching.
+ */
+struct CanMessageFilter {
+    CanMessageId id;
+    uint32_t mask;
+    bool inverted;
+};
+
+enum Result : uint8_t {
+    OK,
+    UNKNOWN_ERROR,
+    PAYLOAD_TOO_LONG,
+    INTERFACE_DOWN,
+    TRANSMISSION_FAILURE,
+    INVALID_ARGUMENTS,
+};
+
+/**
+ * @see ICanMessageListener#onError
+ */
+enum ErrorEvent : uint8_t {
+    UNKNOWN_ERROR,
+
+    /** A problem with CAN interface HW. */
+    HARDWARE_ERROR,
+
+    /** TX buffer overflow: client is sending too many packets. */
+    TX_OVERFLOW,
+
+    /** RX buffer overflow: client is not reading packets fast enough. */
+    RX_OVERFLOW,
+
+    /** Received malformed input. */
+    MALFORMED_INPUT,
+
+    /** Bus overload: there is too much traffic on the bus. */
+    BUS_OVERLOAD,
+
+    /** Bus error: shorted Hi/Lo line, bus off etc. */
+    BUS_ERROR,
+};
diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..b4d9132
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "android.hardware.automotive.can@vts-defaults",
+    defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+        "android.hardware.automotive.can@vts-utils-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libgmock",
+    ],
+    test_suites: ["general-tests"],
+}
+
+cc_test {
+    name: "VtsHalCanControllerV1_0TargetTest",
+    defaults: ["android.hardware.automotive.can@vts-defaults"],
+    srcs: ["VtsHalCanControllerV1_0TargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalCanBusV1_0TargetTest",
+    defaults: ["android.hardware.automotive.can@vts-defaults"],
+    srcs: ["VtsHalCanBusV1_0TargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalCanBusVirtualV1_0TargetTest",
+    defaults: ["android.hardware.automotive.can@vts-defaults"],
+    srcs: ["VtsHalCanBusVirtualV1_0TargetTest.cpp"],
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
new file mode 100644
index 0000000..215328e
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using hardware::hidl_vec;
+
+static utils::SimpleHidlEnvironment<ICanBus>* gEnv = nullptr;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+    virtual Return<void> onReceive(const can::V1_0::CanMessage&) { return {}; }
+    virtual Return<void> onError(can::V1_0::ErrorEvent) { return {}; }
+};
+
+class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    std::tuple<Result, sp<ICloseHandle>> listen(const hidl_vec<CanMessageFilter>& filter,
+                                                const sp<ICanMessageListener>& listener);
+
+    sp<ICanBus> mCanBus;
+};
+
+void CanBusHalTest::SetUp() {
+    const auto serviceName = gEnv->getServiceName<ICanBus>();
+    mCanBus = getService<ICanBus>(serviceName);
+    ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << serviceName;
+}
+
+void CanBusHalTest::TearDown() {
+    mCanBus.clear();
+}
+
+std::tuple<Result, sp<ICloseHandle>> CanBusHalTest::listen(
+        const hidl_vec<CanMessageFilter>& filter, const sp<ICanMessageListener>& listener) {
+    Result halResult;
+    sp<ICloseHandle> closeHandle;
+    mCanBus->listen(filter, listener, hidl_utils::fill(&halResult, &closeHandle)).assertOk();
+
+    return {halResult, closeHandle};
+}
+
+TEST_F(CanBusHalTest, SendNoPayload) {
+    CanMessage msg = {};
+    msg.id = 0x123;
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, Send8B) {
+    CanMessage msg = {};
+    msg.id = 0x234;
+    msg.payload = {1, 2, 3, 4, 5, 6, 7, 8};
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, SendZeroId) {
+    CanMessage msg = {};
+    msg.payload = {1, 2, 3};
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, SendTooLong) {
+    CanMessage msg = {};
+    msg.id = 0x123;
+    msg.payload = hidl_vec<uint8_t>(102400);  // 100kiB
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::PAYLOAD_TOO_LONG, result);
+}
+
+TEST_F(CanBusHalTest, ListenNoFilter) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenSomeFilter) {
+    hidl_vec<CanMessageFilter> filters = {
+            {0x123, 0x1FF, false},
+            {0x001, 0x00F, true},
+            {0x200, 0x100, false},
+    };
+
+    const auto [result, closeHandle] = listen(filters, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenNull) {
+    const auto [result, closeHandle] = listen({}, nullptr);
+    ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
+}
+
+TEST_F(CanBusHalTest, DoubleCloseListen) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DontCloseListen) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+}
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \
+ *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test
+ */
+int main(int argc, char** argv) {
+    using android::hardware::automotive::can::V1_0::ICanBus;
+    using android::hardware::automotive::can::V1_0::vts::gEnv;
+    using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+    android::base::SetDefaultTag("CanBusVts");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    gEnv = new SimpleHidlEnvironment<ICanBus>;
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
new file mode 100644
index 0000000..699c138
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+#include <utils/Mutex.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using namespace std::chrono_literals;
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+    DISALLOW_COPY_AND_ASSIGN(CanMessageListener);
+
+    CanMessageListener() {}
+
+    virtual Return<void> onReceive(const can::V1_0::CanMessage& msg) {
+        std::unique_lock<std::mutex> lk(mMessagesGuard);
+        mMessages.push_back(msg);
+        mMessagesUpdated.notify_one();
+        return {};
+    }
+
+    virtual Return<void> onError(can::V1_0::ErrorEvent event) {
+        EXPECT_TRUE(false) << "Got error: " << event;
+        return {};
+    }
+
+    virtual ~CanMessageListener() { mCloseHandle->close(); }
+
+    void assignCloseHandle(sp<ICloseHandle> closeHandle) {
+        EXPECT_TRUE(closeHandle);
+        EXPECT_FALSE(mCloseHandle);
+        mCloseHandle = closeHandle;
+    }
+
+    std::vector<can::V1_0::CanMessage> fetchMessages(std::chrono::milliseconds timeout,
+                                                     unsigned atLeast = 1) {
+        std::unique_lock<std::mutex> lk(mMessagesGuard);
+        mMessagesUpdated.wait_for(lk, timeout, [&] { return mMessages.size() >= atLeast; });
+        const auto messages = mMessages;
+        mMessages.clear();
+        return messages;
+    }
+
+  private:
+    sp<ICloseHandle> mCloseHandle;
+
+    std::mutex mMessagesGuard;
+    std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard);
+    std::vector<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+};
+
+struct Bus {
+    DISALLOW_COPY_AND_ASSIGN(Bus);
+
+    Bus(sp<ICanController> controller, const ICanController::BusConfiguration& config)
+        : mIfname(config.name), mController(controller) {
+        const auto result = controller->upInterface(config);
+        EXPECT_EQ(ICanController::Result::OK, result);
+
+        /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
+         * file -- this is a test, so we don't want to add dummy services to a device manifest.
+         */
+        auto manager = hidl::manager::V1_2::IServiceManager::getService();
+        auto service = manager->get(ICanBus::descriptor, config.name);
+        mBus = ICanBus::castFrom(service);
+        EXPECT_TRUE(mBus) << "ICanBus/" << config.name << " failed to register";
+    }
+
+    virtual ~Bus() { reset(); }
+
+    void reset() {
+        mBus.clear();
+        if (mController) {
+            const auto res = mController->downInterface(mIfname);
+            EXPECT_TRUE(res);
+            mController.clear();
+        }
+    }
+
+    ICanBus* operator->() const { return mBus.get(); }
+    sp<ICanBus> get() { return mBus; }
+
+    sp<CanMessageListener> listen(const hidl_vec<CanMessageFilter>& filter) {
+        sp<CanMessageListener> listener = new CanMessageListener();
+
+        Result result;
+        sp<ICloseHandle> closeHandle;
+        mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk();
+        EXPECT_EQ(Result::OK, result);
+        listener->assignCloseHandle(closeHandle);
+
+        return listener;
+    }
+
+    void send(const CanMessage& msg) {
+        const auto result = mBus->send(msg);
+        EXPECT_EQ(Result::OK, result);
+    }
+
+  private:
+    const std::string mIfname;
+    sp<ICanController> mController;
+    sp<ICanBus> mBus;
+};
+
+class CanBusVirtualHalTest : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
+    virtual void SetUp() override;
+
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+    Bus makeBus();
+
+  private:
+    unsigned mLastIface = 0;
+    static sp<ICanController> mCanController;
+    static bool mVirtualSupported;
+};
+
+sp<ICanController> CanBusVirtualHalTest::mCanController = nullptr;
+bool CanBusVirtualHalTest::mVirtualSupported;
+
+static CanMessage makeMessage(CanMessageId id) {
+    CanMessage msg = {};
+    msg.id = id;
+    return msg;
+}
+
+static void clearTimestamps(std::vector<CanMessage>& messages) {
+    std::for_each(messages.begin(), messages.end(), [](auto& msg) { msg.timestamp = 0; });
+}
+
+void CanBusVirtualHalTest::SetUp() {
+    if (!mVirtualSupported) GTEST_SKIP();
+}
+
+void CanBusVirtualHalTest::SetUpTestCase() {
+    const auto serviceName = gEnv->getServiceName<ICanController>();
+    mCanController = getService<ICanController>(serviceName);
+    ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
+
+    hidl_vec<InterfaceType> supported;
+    mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk();
+    mVirtualSupported = supported.contains(InterfaceType::VIRTUAL);
+}
+
+void CanBusVirtualHalTest::TearDownTestCase() {
+    mCanController.clear();
+}
+
+Bus CanBusVirtualHalTest::makeBus() {
+    const auto idx = ++mLastIface;
+
+    ICanController::BusConfiguration config = {};
+    config.name = "test" + std::to_string(idx);
+    config.iftype = InterfaceType::VIRTUAL;
+    config.interfaceId.address("vcan50");
+
+    return Bus(mCanController, config);
+}
+
+TEST_F(CanBusVirtualHalTest, Send) {
+    auto bus = makeBus();
+
+    CanMessage msg = {};
+    msg.id = 0x123;
+    msg.payload = {1, 2, 3};
+
+    bus.send(msg);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAfterClose) {
+    auto bus = makeBus();
+    auto zombie = bus.get();
+    bus.reset();
+
+    const auto result = zombie->send({});
+    ASSERT_EQ(Result::INTERFACE_DOWN, result);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAndRecv) {
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    auto listener = bus2.listen({});
+
+    CanMessage msg = {};
+    msg.id = 0x123;
+    msg.payload = {1, 2, 3};
+    bus1.send(msg);
+
+    auto messages = listener->fetchMessages(100ms);
+    ASSERT_EQ(1u, messages.size());
+    ASSERT_NEAR(uint64_t(elapsedRealtimeNano()), messages[0].timestamp,
+                std::chrono::nanoseconds(100ms).count());
+    clearTimestamps(messages);
+    ASSERT_EQ(msg, messages[0]);
+}
+
+TEST_F(CanBusVirtualHalTest, DownOneOfTwo) {
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    bus2.reset();
+
+    bus1.send({});
+}
+
+TEST_F(CanBusVirtualHalTest, Filter) {
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    hidl_vec<CanMessageFilter> filterPositive = {
+            {0x101, 0x100, false},
+            {0x010, 0x0F0, false},
+    };
+    auto listenerPositive = bus2.listen(filterPositive);
+
+    hidl_vec<CanMessageFilter> filterNegative = {
+            {0x123, 0x0FF, true},
+            {0x004, 0x00F, true},
+    };
+    auto listenerNegative = bus2.listen(filterNegative);
+
+    bus1.send(makeMessage(0));
+    bus1.send(makeMessage(0x1A0));
+    bus1.send(makeMessage(0x1A1));
+    bus1.send(makeMessage(0x2A0));
+    bus1.send(makeMessage(0x3A0));
+    bus1.send(makeMessage(0x010));
+    bus1.send(makeMessage(0x123));
+    bus1.send(makeMessage(0x023));
+    bus1.send(makeMessage(0x124));
+
+    std::vector<can::V1_0::CanMessage> expectedPositive{
+            makeMessage(0x1A0),  //
+            makeMessage(0x1A1),  //
+            makeMessage(0x3A0),  //
+            makeMessage(0x010),  //
+            makeMessage(0x123),  //
+            makeMessage(0x124),  //
+    };
+    std::vector<can::V1_0::CanMessage> expectedNegative{
+            makeMessage(0),      //
+            makeMessage(0x1A0),  //
+            makeMessage(0x1A1),  //
+            makeMessage(0x2A0),  //
+            makeMessage(0x3A0),  //
+            makeMessage(0x010),  //
+    };
+
+    auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
+    auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
+    clearTimestamps(messagesNegative);
+    clearTimestamps(messagesPositive);
+    ASSERT_EQ(expectedNegative, messagesNegative);
+    ASSERT_EQ(expectedPositive, messagesPositive);
+}
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest\
+ *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+    using android::hardware::automotive::can::V1_0::ICanController;
+    using android::hardware::automotive::can::V1_0::vts::gEnv;
+    using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+    android::base::SetDefaultTag("CanBusVirtualVts");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    gEnv = new SimpleHidlEnvironment<ICanController>;
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
new file mode 100644
index 0000000..70f9fe4
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    hidl_vec<InterfaceType> getSupportedInterfaceTypes();
+    bool isSupported(InterfaceType iftype);
+
+    bool up(InterfaceType iftype, const std::string srvname, std::string ifname,
+            ICanController::Result expected);
+    void assertRegistered(const std::string srvname, bool expectRegistered);
+
+    sp<ICanController> mCanController;
+};
+
+void CanControllerHalTest::SetUp() {
+    const auto serviceName = gEnv->getServiceName<ICanController>();
+    mCanController = getService<ICanController>(serviceName);
+    ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
+}
+
+void CanControllerHalTest::TearDown() {
+    mCanController.clear();
+}
+
+hidl_vec<InterfaceType> CanControllerHalTest::getSupportedInterfaceTypes() {
+    hidl_vec<InterfaceType> iftypesResult;
+    mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk();
+    return iftypesResult;
+}
+
+bool CanControllerHalTest::isSupported(InterfaceType iftype) {
+    const auto supported = getSupportedInterfaceTypes();
+    return std::find(supported.begin(), supported.end(), iftype) != supported.end();
+}
+
+bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname,
+                              ICanController::Result expected) {
+    ICanController::BusConfiguration config = {};
+    config.name = srvname;
+    config.iftype = iftype;
+    config.interfaceId.address(ifname);
+
+    const auto upresult = mCanController->upInterface(config);
+
+    if (!isSupported(iftype)) {
+        LOG(INFO) << iftype << " interfaces not supported";
+        EXPECT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+        return false;
+    }
+
+    EXPECT_EQ(expected, upresult);
+    return true;
+}
+
+void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
+    /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
+     * file -- this is a test, so we don't want to add dummy services to a device manifest.
+     */
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    auto busService = manager->get(ICanBus::descriptor, srvname);
+    ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
+            << "ICanBus/" << srvname << (expectRegistered ? " is not " : " is ") << "registered"
+            << " (should be otherwise)";
+}
+
+TEST_F(CanControllerHalTest, SupportsSomething) {
+    const auto supported = getSupportedInterfaceTypes();
+    ASSERT_GT(supported.size(), 0u);
+}
+
+TEST_F(CanControllerHalTest, BringUpDown) {
+    const std::string name = "dummy";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP();
+    assertRegistered(name, true);
+
+    const auto dnresult = mCanController->downInterface(name);
+    ASSERT_TRUE(dnresult);
+
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, DownDummy) {
+    const auto result = mCanController->downInterface("imnotup");
+    ASSERT_FALSE(result);
+}
+
+TEST_F(CanControllerHalTest, UpTwice) {
+    const std::string name = "dummy";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP();
+    assertRegistered(name, true);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan73", ICanController::Result::INVALID_STATE)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, true);
+
+    const auto result = mCanController->downInterface(name);
+    ASSERT_TRUE(result);
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, IdentifierCompatibility) {
+    using IdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
+    static const std::map<InterfaceType, std::vector<IdDisc>> compatMatrix = {
+            {InterfaceType::VIRTUAL, {IdDisc::address}},
+            {InterfaceType::SOCKETCAN, {IdDisc::address, IdDisc::serialno}},
+            {InterfaceType::SLCAN, {IdDisc::address, IdDisc::serialno}},
+            {InterfaceType::INDEXED, {IdDisc::index}},
+    };
+    static const std::vector<IdDisc> allDisc = {IdDisc::address, IdDisc::index, IdDisc::serialno};
+
+    for (const auto [iftype, supported] : compatMatrix) {
+        for (const auto iddisc : allDisc) {
+            LOG(INFO) << "Compatibility testing: " << iftype << " / " << iddisc;
+
+            ICanController::BusConfiguration config = {};
+            config.name = "compattestsrv";
+            config.iftype = iftype;
+            config.baudrate = 125000;
+
+            // using random-ish addresses, which may not be valid - we can't test the success case
+            if (iddisc == IdDisc::address) {
+                config.interfaceId.address("can0");
+            } else if (iddisc == IdDisc::index) {
+                config.interfaceId.index(0);
+            } else if (iddisc == IdDisc::serialno) {
+                config.interfaceId.serialno({"dummy", "dummier"});
+            }
+
+            const auto upresult = mCanController->upInterface(config);
+
+            if (!isSupported(iftype)) {
+                ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+                continue;
+            }
+            ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
+
+            bool isSupportedDisc =
+                    std::find(supported.begin(), supported.end(), iddisc) != supported.end();
+            if (!isSupportedDisc) {
+                ASSERT_EQ(ICanController::Result::BAD_ADDRESS, upresult);
+                continue;
+            }
+
+            if (upresult == ICanController::Result::OK) {
+                const auto dnresult = mCanController->downInterface(config.name);
+                ASSERT_TRUE(dnresult);
+                continue;
+            }
+        }
+    }
+}
+
+TEST_F(CanControllerHalTest, FailEmptyName) {
+    const std::string name = "";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadName) {
+    // 33 characters (name can be at most 32 characters long)
+    const std::string name = "ab012345678901234567890123456789c";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadVirtualAddress) {
+    const std::string name = "dummy";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadSocketcanAddress) {
+    const std::string name = "dummy";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest\
+ *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+    using android::hardware::automotive::can::V1_0::ICanController;
+    using android::hardware::automotive::can::V1_0::vts::gEnv;
+    using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+    android::base::SetDefaultTag("CanControllerVts");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    gEnv = new SimpleHidlEnvironment<ICanController>;
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp
new file mode 100644
index 0000000..e925c8f
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/Android.bp
@@ -0,0 +1,20 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "android.hardware.automotive.can@vts-utils-lib",
+    export_include_dirs: ["include"],
+}
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
new file mode 100644
index 0000000..0923998
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+
+/**
+ * Define gTest printer for a given HIDL type, but skip definition for Return<T>.
+ */
+#define DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \
+    std::ostream& operator<<(std::ostream& os, const T& v) { return os << converter(v); }
+
+/**
+ * Define gTest printer for a given HIDL type.
+ */
+#define DEFINE_CAN_HAL_PRINTER(T, converter)    \
+    DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \
+    std::ostream& operator<<(std::ostream& os, const Return<T>& v) { return os << converter(v); }
+
+DEFINE_CAN_HAL_PRINTER(CanMessage, toString)
+DEFINE_CAN_HAL_PRINTER(ErrorEvent, toString)
+DEFINE_CAN_HAL_PRINTER_SIMPLE(
+        ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator, int)
+DEFINE_CAN_HAL_PRINTER(ICanController::InterfaceType, toString)
+DEFINE_CAN_HAL_PRINTER(ICanController::Result, toString)
+DEFINE_CAN_HAL_PRINTER(Result, toString)
+
+#undef DEFINE_CAN_HAL_PRINTER
+#undef DEFINE_CAN_HAL_PRINTER_SIMPLE
+
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
new file mode 100644
index 0000000..a722dd0
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+namespace utils {
+
+/**
+ * Simple test environment.
+ *
+ * This is a helper class to instantiate a test environment without boilerplate code for cases where
+ * there is no need to pass more parameters than just HIDL service instance name.
+ *
+ * The class implements registerTestServices() by calling registerTestService() on every HIDL
+ * interface provided as parameter to this template.
+ *
+ * Example usage:
+ *     static utils::SimpleHidlEnvironment<IMyService>* gEnv = nullptr;
+ *
+ *     void CanBusHalTest::SetUp() {
+ *         const auto serviceName = gEnv->getServiceName<IMyService>();
+ *         (...)
+ *     }
+ *
+ *     int main(int argc, char** argv) {
+ *         gEnv = new SimpleHidlEnvironment<IMyService>;
+ *         ::testing::AddGlobalTestEnvironment(gEnv);
+ *         ::testing::InitGoogleTest(&argc, argv);
+ *         gEnv->init(&argc, argv);
+ *         return RUN_ALL_TESTS();
+ *     }
+ *
+ * \param T... HIDL interface names to register for a test service
+ */
+template <typename... T>
+class SimpleHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    virtual void registerTestServices() override {
+        // Call registerTestService() for every HIDL interface using this template.
+        using expander = int[];
+        (void)expander{0, (registerTestService<T>(), 0)...};
+    }
+};
+
+}  // namespace utils
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index e7f6bb7..21ca79e 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -17,6 +17,7 @@
 package android.hardware.automotive.evs@1.1;
 
 import @1.0::IEvsCamera;
+import @1.0::IEvsDisplay;
 import @1.0::EvsResult;
 import IEvsCameraStream;
 
@@ -54,4 +55,76 @@
      * @return result Return EvsResult::OK if this call is successful.
      */
     doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result);
+
+    /**
+     * Requests to be a master client.
+     *
+     * When multiple clients subscribe to a single camera hardware and one of
+     * them adjusts a camera parameter such as the contrast, it may disturb
+     * other clients' operations.  Therefore, the client must call this method
+     * to be a master client.  Once it becomes a master, it will be able to
+     * change camera parameters until either it dies or explicitly gives up the
+     * role.
+     *
+     * @return result EvsResult::OK if a master role is granted.
+     *                EvsResult::OWNERSHIP_LOST if there is already a
+     *                master client.
+     */
+    setMaster() generates (EvsResult result);
+
+    /**
+     * Sets to be a master client forcibly.
+     *
+     * The client, which owns the display, has a high priority and can take over
+     * a master role from other clients without the display.
+     *
+     * @param  display IEvsDisplay handle.  If a given display is in either
+     *                 NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the
+     *                 calling client is considered as the high priority client
+     *                 and therefore allowed to take over a master role from
+     *                 existing master client.
+     *
+     * @return result  EvsResult::OK if a master role is granted.
+     *                 EvsResult::INVALID_ARG if a given display handle is null
+     *                 or in valid states.
+     */
+    forceMaster(IEvsDisplay display) generates (EvsResult result);
+
+    /**
+     * Retires from a master client role.
+     *
+     * @return result EvsResult::OK if this call is successful.
+     *                EvsResult::INVALID_ARG if the caller client is not a
+     *                master client.
+     */
+    unsetMaster() generates (EvsResult result);
+
+    /**
+     * Requests to set a camera parameter.
+     *
+     * @param  id             The identifier of camera parameter, CameraParam enum.
+     *         value          A desired parameter value.
+     * @return result         EvsResult::OK if it succeeds to set a parameter.
+     *                        EvsResult::INVALID_ARG if either the request is
+     *                        not made by a master client, or a requested
+     *                        parameter is not supported.
+     *                        EvsResult::UNDERLYING_SERVICE_ERROR if it fails to
+     *                        program a value by any other reason.
+     *         effectiveValue A programmed parameter value.  This may differ
+     *                        from what the client gives if, for example, the
+     *                        driver does not support a target parameter.
+     */
+    setParameter(CameraParam id, int32_t value)
+        generates (EvsResult result, int32_t effectiveValue);
+
+    /**
+     * Retrieves a value of given camera parameter.
+     *
+     * @param  id     The identifier of camera parameter, CameraParam enum.
+     * @return result EvsResult::OK if it succeeds to read a parameter.
+     *                EvsResult::INVALID_ARG if either a requested parameter is
+     *                not supported.
+     *         value  A value of requested camera parameter.
+     */
+    getParameter(CameraParam id) generates(EvsResult result, int32_t value);
 };
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
index cd058a5..7c7f832 100644
--- a/automotive/evs/1.1/IEvsCameraStream.hal
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -19,7 +19,7 @@
 import @1.0::IEvsCameraStream;
 
 /**
- * Implemented on client side to receive asynchronous video frame deliveries.
+ * Implemented on client side to receive asynchronous streaming event deliveries.
  */
 interface IEvsCameraStream extends @1.0::IEvsCameraStream {
     /**
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 62d9826..2d55566 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -258,6 +258,44 @@
 }
 
 
+Return<EvsResult> EvsCamera::setMaster() {
+    // Default implementation does not expect multiple subscribers and therefore
+    // return a success code always.
+    return EvsResult::OK;
+}
+
+Return<EvsResult> EvsCamera::forceMaster(const sp<IEvsDisplay>& ) {
+    // Default implementation does not expect multiple subscribers and therefore
+    // return a success code always.
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsCamera::unsetMaster() {
+    // Default implementation does not expect multiple subscribers and therefore
+    // return a success code always.
+    return EvsResult::OK;
+}
+
+
+Return<void> EvsCamera::setParameter(CameraParam id, int32_t value,
+                                     setParameter_cb _hidl_cb) {
+    // Default implementation does not support this.
+    (void)id;
+    (void)value;
+    _hidl_cb(EvsResult::INVALID_ARG, 0);
+    return Void();
+}
+
+
+Return<void> EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) {
+    // Default implementation does not support this.
+    (void)id;
+    _hidl_cb(EvsResult::INVALID_ARG, 0);
+    return Void();
+}
+
+
 bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
     if (bufferCount < 1) {
         ALOGE("Ignoring request to set buffer count to zero");
@@ -468,7 +506,9 @@
 
     // If we've been asked to stop, send an event to signal the actual end of stream
     EvsEvent event;
-    event.info(EvsEventType::STREAM_STOPPED);
+    InfoEventDesc desc = {};
+    desc.aType = InfoEventType::STREAM_STOPPED;
+    event.info(desc);
     auto result = mStream->notifyEvent(event);
     if (!result.isOk()) {
         ALOGE("Error delivering end of stream marker");
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index 0982464..47a3164 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -20,6 +20,7 @@
 #include <android/hardware/automotive/evs/1.1/types.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
 #include <ui/GraphicBuffer.h>
 
 #include <thread>
@@ -30,6 +31,7 @@
 using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
 
 
 namespace android {
@@ -60,6 +62,12 @@
     Return<EvsResult> pauseVideoStream() override;
     Return<EvsResult> resumeVideoStream() override;
     Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
+    Return<EvsResult> setMaster() override;
+    Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
+    Return<EvsResult> unsetMaster() override;
+    Return<void>      setParameter(CameraParam id, int32_t value,
+                                   setParameter_cb _hidl_cb) override;
+    Return<void>      getParameter(CameraParam id, getParameter_cb _hidl_cb) override;
 
     // Implementation details
     EvsCamera(const char *id);
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index ff6ab4e..2c6b2ed 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -48,9 +48,9 @@
 };
 
 /**
- * EVS event types
+ * Types of informative streaming events
  */
-enum EvsEventType : uint32_t {
+enum InfoEventType : uint32_t {
     /**
      * Video stream is started
      */
@@ -67,6 +67,29 @@
      * Timeout happens
      */
     TIMEOUT,
+    /**
+     * Camera parameter is changed; payload contains a changed parameter ID and
+     * its value
+     */
+    PARAMETER_CHANGED,
+    /**
+     * Master role has become available
+     */
+    MASTER_RELEASED,
+};
+
+/**
+ * Structure that describes informative events occurred during EVS is streaming
+ */
+struct InfoEventDesc {
+    /**
+     * Type of an informative event
+     */
+    InfoEventType aType;
+    /**
+     * Possible additional information
+     */
+    uint32_t[4] payload;
 };
 
 /**
@@ -80,5 +103,74 @@
     /**
      * General streaming events
      */
-    EvsEventType info;
+    InfoEventDesc info;
+};
+
+/**
+ * EVS Camera Parameter
+ */
+enum CameraParam : uint32_t {
+    /**
+     * The brightness of image frames
+     */
+    BRIGHTNESS,
+    /**
+     * The contrast of image frames
+     */
+    CONTRAST,
+    /**
+     * Automatic gain/exposure control
+     */
+    AUTOGAIN,
+    /**
+     * Gain control
+     */
+    GAIN,
+    /**
+     * Mirror the image horizontally
+     */
+    HFLIP,
+    /**
+     * Mirror the image vertically
+     */
+    VFLIP,
+    /**
+     * Automatic Whitebalance
+     */
+    AUTO_WHITE_BALANCE,
+    /**
+     * Manual white balance setting as a color temperature in Kelvin.
+     */
+    WHITE_BALANCE_TEMPERATURE,
+    /**
+     * Image sharpness adjustment
+     */
+    SHARPNESS,
+    /**
+     * Auto Exposure Control modes; auto, manual, shutter priority, or
+     * aperture priority.
+     */
+    AUTO_EXPOSURE,
+    /**
+     * Manual exposure time of the camera
+     */
+    ABSOLUTE_EXPOSURE,
+    /**
+     * When AEC is running in either auto or aperture priority, this parameter
+     * sets whether a frame rate varies.
+     */
+    AUTO_EXPOSURE_PRIORITY,
+    /**
+     * Set the focal point of the camera to the specified position.  This
+     * parameter may not be effective when auto focus is enabled.
+     */
+    ABSOLUTE_FOCUS,
+    /**
+     * Enables continuous automatic focus adjustments.
+     */
+    AUTO_FOCUS,
+    /**
+     * Specify the objective lens focal length as an absolute value.
+     */
+    ABSOLUTE_ZOOM,
 };
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index b7c7f21..1627689 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -21,11 +21,14 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <chrono>
 
 #include <android/log.h>
 #include <cutils/native_handle.h>
 #include <ui/GraphicBuffer.h>
 
+using namespace std::chrono_literals;
+
 FrameHandler::FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
                            android::sp <IEvsDisplay> pDisplay,
                            BufferControlFlag mode) :
@@ -79,7 +82,7 @@
     // Wait until the stream has actually stopped
     std::unique_lock<std::mutex> lock(mLock);
     if (mRunning) {
-        mSignal.wait(lock, [this]() { return !mRunning; });
+        mEventSignal.wait(lock, [this]() { return !mRunning; });
     }
 }
 
@@ -110,7 +113,9 @@
 void FrameHandler::waitForFrameCount(unsigned frameCount) {
     // Wait until we've seen at least the requested number of frames (could be more)
     std::unique_lock<std::mutex> lock(mLock);
-    mSignal.wait(lock, [this, frameCount](){ return mFramesReceived >= frameCount; });
+    mFrameSignal.wait(lock, [this, frameCount](){
+                                return mFramesReceived >= frameCount;
+                            });
 }
 
 
@@ -135,16 +140,21 @@
 
 Return<void> FrameHandler::notifyEvent(const EvsEvent& event) {
     // Local flag we use to keep track of when the stream is stopping
-    bool timeToStop = false;
-
     auto type = event.getDiscriminator();
     if (type == EvsEvent::hidl_discriminator::info) {
-        if (event.info() == EvsEventType::STREAM_STOPPED) {
+        mLock.lock();
+        mLatestEventDesc = event.info();
+        if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) {
             // Signal that the last frame has been received and the stream is stopped
-            timeToStop = true;
+            mRunning = false;
+        } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) {
+            ALOGD("Camera parameter 0x%X is changed to 0x%X",
+                  mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
         } else {
-            ALOGD("Received an event 0x%X", event.info());
+            ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
         }
+        mLock.unlock();
+        mEventSignal.notify_all();
     } else {
         auto bufDesc = event.buffer();
         const AHardwareBuffer_Desc* pDesc =
@@ -207,21 +217,14 @@
             mHeldBuffers.push(bufDesc);
         }
 
+        mLock.lock();
+        ++mFramesReceived;
+        mLock.unlock();
+        mFrameSignal.notify_all();
 
         ALOGD("Frame handling complete");
     }
 
-
-    // Update our received frame count and notify anybody who cares that things have changed
-    mLock.lock();
-    if (timeToStop) {
-        mRunning = false;
-    } else {
-        mFramesReceived++;
-    }
-    mLock.unlock();
-    mSignal.notify_all();
-
     return Void();
 }
 
@@ -338,3 +341,43 @@
         *height = mFrameHeight;
     }
 }
+
+bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent,
+                                InfoEventDesc &eventDesc) {
+    // Wait until we get an expected parameter change event.
+    std::unique_lock<std::mutex> lock(mLock);
+    auto now = std::chrono::system_clock::now();
+    bool result = mEventSignal.wait_until(lock, now + 5s,
+        [this, aTargetEvent, &eventDesc](){
+            bool flag = mLatestEventDesc.aType == aTargetEvent;
+            if (flag) {
+                eventDesc.aType = mLatestEventDesc.aType;
+                eventDesc.payload[0] = mLatestEventDesc.payload[0];
+                eventDesc.payload[1] = mLatestEventDesc.payload[1];
+            }
+
+            return flag;
+        }
+    );
+
+    return !result;
+}
+
+const char *FrameHandler::eventToString(const InfoEventType aType) {
+    switch (aType) {
+        case InfoEventType::STREAM_STARTED:
+            return "STREAM_STARTED";
+        case InfoEventType::STREAM_STOPPED:
+            return "STREAM_STOPPED";
+        case InfoEventType::FRAME_DROPPED:
+            return "FRAME_DROPPED";
+        case InfoEventType::TIMEOUT:
+            return "TIMEOUT";
+        case InfoEventType::PARAMETER_CHANGED:
+            return "PARAMETER_CHANGED";
+        case InfoEventType::MASTER_RELEASED:
+            return "MASTER_RELEASED";
+        default:
+            return "Unknown";
+    }
+}
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index 49fa736..7f87cb4 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -67,6 +67,8 @@
     bool isRunning();
 
     void waitForFrameCount(unsigned frameCount);
+    bool waitForEvent(const InfoEventType aTargetEvent,
+                            InfoEventDesc &eventDesc);
     void getFramesCounters(unsigned* received, unsigned* displayed);
     void getFrameDimension(unsigned* width, unsigned* height);
 
@@ -77,6 +79,7 @@
 
     // Local implementation details
     bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
+    const char *eventToString(const InfoEventType aType);
 
     // Values initialized as startup
     android::sp <IEvsCamera>    mCamera;
@@ -88,7 +91,8 @@
     // we need to protect all member variables that may be modified while we're streaming
     // (ie: those below)
     std::mutex                  mLock;
-    std::condition_variable     mSignal;
+    std::condition_variable     mEventSignal;
+    std::condition_variable     mFrameSignal;
 
     std::queue<BufferDesc_1_1>  mHeldBuffers;
     bool                        mRunning = false;
@@ -96,6 +100,7 @@
     unsigned                    mFramesDisplayed = 0;   // Simple counter -- rolls over eventually!
     unsigned                    mFrameWidth = 0;
     unsigned                    mFrameHeight = 0;
+    InfoEventDesc               mLatestEventDesc;
 };
 
 
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 4f7082a..a6e4881 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -124,8 +124,8 @@
 
     sp<IEvsEnumerator>        pEnumerator;    // Every test needs access to the service
     std::vector <CameraDesc>  cameraInfo;     // Empty unless/until loadCameraList() is called
-    bool                        mIsHwModule;    // boolean to tell current module under testing
-                                                // is HW module implementation.
+    bool                      mIsHwModule;    // boolean to tell current module under testing
+                                              // is HW module implementation.
 };
 
 
@@ -516,6 +516,551 @@
 }
 
 
+/*
+ * CameraParameter:
+ * Verify that a client can adjust a camera parameter.
+ */
+TEST_F(EvsHidlTest, CameraParameter) {
+    ALOGI("Starting CameraParameter test");
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // Create a camera client
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         nullptr,
+                                                         FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler, nullptr);
+
+        // Start the camera's video stream
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandler->waitForFrameCount(1);
+
+        // Try to program few parameters
+        EvsResult result = EvsResult::OK;
+        int32_t val0 = 100;
+        int32_t val1 = 0;
+
+        result = pCam->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        pCam->setParameter(CameraParam::BRIGHTNESS, val0,
+                           [&result, &val1](auto status, auto effectiveValue) {
+                               result = status;
+                               val1 = effectiveValue;
+                           });
+        ASSERT_TRUE(result == EvsResult::OK ||
+                    result == EvsResult::INVALID_ARG);
+
+        if (result == EvsResult::OK) {
+            pCam->getParameter(CameraParam::BRIGHTNESS,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            ASSERT_TRUE(result == EvsResult::OK ||
+                        result == EvsResult::INVALID_ARG);
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+        }
+
+        val0 = 80;
+        val1 = 0;
+        pCam->setParameter(CameraParam::CONTRAST, val0,
+                           [&result, &val1](auto status, auto effectiveValue) {
+                               result = status;
+                               val1 = effectiveValue;
+                           });
+        ASSERT_TRUE(result == EvsResult::OK ||
+                    result == EvsResult::INVALID_ARG);
+
+        if (result == EvsResult::OK) {
+            pCam->getParameter(CameraParam::CONTRAST,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            ASSERT_TRUE(result == EvsResult::OK ||
+                        result == EvsResult::INVALID_ARG);
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+        }
+
+        val0 = 300;
+        val1 = 0;
+        pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0,
+                           [&result, &val1](auto status, auto effectiveValue) {
+                               result = status;
+                               val1 = effectiveValue;
+                           });
+        ASSERT_TRUE(result == EvsResult::OK ||
+                    result == EvsResult::INVALID_ARG);
+
+        if (result == EvsResult::OK) {
+            pCam->getParameter(CameraParam::ABSOLUTE_ZOOM,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            ASSERT_TRUE(result == EvsResult::OK ||
+                        result == EvsResult::INVALID_ARG);
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+        }
+
+        result = pCam->unsetMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Shutdown
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+    }
+}
+
+
+/*
+ * CameraMasterRelease
+ * Verify that non-master client gets notified when the master client either
+ * terminates or releases a role.
+ */
+TEST_F(EvsHidlTest, CameraMasterRelease) {
+    ALOGI("Starting CameraMasterRelease test");
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // Create two camera clients.
+        sp<IEvsCamera_1_1> pCamMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamMaster, nullptr);
+        sp<IEvsCamera_1_1> pCamNonMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamNonMaster, nullptr);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandlerMaster =
+            new FrameHandler(pCamMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerMaster, nullptr);
+        sp<FrameHandler> frameHandlerNonMaster =
+            new FrameHandler(pCamNonMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerNonMaster, nullptr);
+
+        // Set one client as the master
+        EvsResult result = pCamMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Try to set another client as the master.
+        result = pCamNonMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+
+        // Start the camera's video stream via a master client.
+        bool startResult = frameHandlerMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerMaster->waitForFrameCount(1);
+
+        // Start the camera's video stream via another client
+        startResult = frameHandlerNonMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerNonMaster->waitForFrameCount(1);
+
+        // Non-master client expects to receive a master role relesed
+        // notification.
+        InfoEventDesc aNotification = {};
+
+        // Release a master role.
+        pCamMaster->unsetMaster();
+
+        // Verify a change notification.
+        frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(InfoEventType::MASTER_RELEASED,
+                  static_cast<InfoEventType>(aNotification.aType));
+
+        // Non-master becomes a master.
+        result = pCamNonMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Previous master client fails to become a master.
+        result = pCamMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+
+        // Closing current master client.
+        frameHandlerNonMaster->shutdown();
+
+        // Verify a change notification.
+        frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(InfoEventType::MASTER_RELEASED,
+                  static_cast<InfoEventType>(aNotification.aType));
+
+        // Closing another stream.
+        frameHandlerMaster->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCamMaster);
+        pEnumerator->closeCamera(pCamNonMaster);
+    }
+
+
+}
+
+
+/*
+ * MultiCameraParameter:
+ * Verify that master and non-master clients behave as expected when they try to adjust
+ * camera parameters.
+ */
+TEST_F(EvsHidlTest, MultiCameraParameter) {
+    ALOGI("Starting MultiCameraParameter test");
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // Create two camera clients.
+        sp<IEvsCamera_1_1> pCamMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamMaster, nullptr);
+        sp<IEvsCamera_1_1> pCamNonMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamNonMaster, nullptr);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandlerMaster =
+            new FrameHandler(pCamMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerMaster, nullptr);
+        sp<FrameHandler> frameHandlerNonMaster =
+            new FrameHandler(pCamNonMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerNonMaster, nullptr);
+
+        // Set one client as the master
+        EvsResult result = pCamMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Try to set another client as the master.
+        result = pCamNonMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+
+        // Start the camera's video stream via a master client.
+        bool startResult = frameHandlerMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerMaster->waitForFrameCount(1);
+
+        // Start the camera's video stream via another client
+        startResult = frameHandlerNonMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerNonMaster->waitForFrameCount(1);
+
+        // Try to program CameraParam::BRIGHTNESS
+        int32_t val0 = 100;
+        int32_t val1 = 0;
+
+        pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
+                                 [&result, &val1](auto status, auto effectiveValue) {
+                                     result = status;
+                                     val1 = effectiveValue;
+                                 });
+        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
+                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
+
+        // Non-master client expects to receive a parameter change notification
+        // whenever a master client adjusts it.
+        InfoEventDesc aNotification = {};
+
+        pCamMaster->getParameter(CameraParam::BRIGHTNESS,
+                                 [&result, &val1](auto status, auto value) {
+                                     result = status;
+                                     if (status == EvsResult::OK) {
+                                        val1 = value;
+                                     }
+                                 });
+        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
+                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
+        if (result == EvsResult::OK) {
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+            // Verify a change notification
+            frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
+                      static_cast<InfoEventType>(aNotification.aType));
+            ASSERT_EQ(CameraParam::BRIGHTNESS,
+                      static_cast<CameraParam>(aNotification.payload[0]));
+            ASSERT_EQ(val1,
+                      static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // Try to program CameraParam::CONTRAST
+        val0 = 80;
+        val1 = 0;
+        pCamMaster->setParameter(CameraParam::CONTRAST, val0,
+                                 [&result, &val1](auto status, auto effectiveValue) {
+                                     result = status;
+                                     val1 = effectiveValue;
+                                 });
+        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
+                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
+
+        if (result == EvsResult::OK) {
+            pCamMaster->getParameter(CameraParam::CONTRAST,
+                                     [&result, &val1](auto status, auto value) {
+                                         result = status;
+                                         if (status == EvsResult::OK) {
+                                            val1 = value;
+                                         }
+                                     });
+            ASSERT_TRUE(result == EvsResult::OK);
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+
+            // Verify a change notification
+            frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
+                      static_cast<InfoEventType>(aNotification.aType));
+            ASSERT_EQ(CameraParam::CONTRAST,
+                      static_cast<CameraParam>(aNotification.payload[0]));
+            ASSERT_EQ(val1,
+                      static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // Try to adjust a parameter via non-master client
+        pCamNonMaster->setParameter(CameraParam::CONTRAST, val0,
+                                    [&result, &val1](auto status, auto effectiveValue) {
+                                        result = status;
+                                        val1 = effectiveValue;
+                                    });
+        ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+
+        // Non-master client attemps to be a master
+        result = pCamNonMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+
+        // Master client retires from a master role
+        result = pCamMaster->unsetMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Try to adjust a parameter after being retired
+        pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
+                                 [&result, &val1](auto status, auto effectiveValue) {
+                                     result = status;
+                                     val1 = effectiveValue;
+                                 });
+        ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+
+        // Non-master client becomes a master
+        result = pCamNonMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Try to adjust a parameter via new master client
+        pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0,
+                                    [&result, &val1](auto status, auto effectiveValue) {
+                                        result = status;
+                                        val1 = effectiveValue;
+                                    });
+        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
+                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
+
+        // Wait a moment
+        sleep(1);
+
+        // Verify a change notification
+        if (result == EvsResult::OK) {
+            frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
+                      InfoEventType::PARAMETER_CHANGED);
+            ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                      CameraParam::BRIGHTNESS);
+            ASSERT_EQ(val1,
+                      static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // New master retires from a master role
+        result = pCamNonMaster->unsetMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Shutdown
+        frameHandlerMaster->shutdown();
+        frameHandlerNonMaster->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCamMaster);
+        pEnumerator->closeCamera(pCamNonMaster);
+    }
+}
+
+
+/*
+ * HighPriorityCameraClient:
+ * EVS client, which owns the display, is priortized and therefore can take over
+ * a master role from other EVS clients without the display.
+ */
+TEST_F(EvsHidlTest, HighPriorityCameraClient) {
+    ALOGI("Starting HighPriorityCameraClient test");
+
+    // Get the camera list
+    loadCameraList();
+
+    // Request exclusive access to the EVS display
+    sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+    ASSERT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // Create two clients
+        sp<IEvsCamera_1_1> pCam0 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam0, nullptr);
+
+        sp<IEvsCamera_1_1> pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam1, nullptr);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+                                                          pDisplay,
+                                                          FrameHandler::eAutoReturn);
+        sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+
+        // Activate the display
+        pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler0->startStream());
+        ASSERT_TRUE(frameHandler1->startStream());
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        // Client 1 becomes a master and programs a brightness.
+        EvsResult result = EvsResult::OK;
+        int32_t val0 = 100;
+        int32_t val1 = 0;
+
+        result = pCam1->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        pCam1->setParameter(CameraParam::BRIGHTNESS, val0,
+                            [&result, &val1](auto status, auto effectiveValue) {
+                                result = status;
+                                val1 = effectiveValue;
+                            });
+        ASSERT_TRUE(result == EvsResult::OK ||
+                    result == EvsResult::INVALID_ARG);
+
+
+        // Verify a change notification
+        InfoEventDesc aNotification = {};
+        if (result == EvsResult::OK) {
+            bool timeout =
+                frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_FALSE(timeout) << "Expected event does not arrive";
+            ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
+                      InfoEventType::PARAMETER_CHANGED);
+            ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                      CameraParam::BRIGHTNESS);
+            ASSERT_EQ(val1,
+                      static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // Client 0 steals a master role
+        ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
+
+        frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
+                  InfoEventType::MASTER_RELEASED);
+
+        // Client 0 programs a brightness
+        val0 = 50;
+        val1 = 0;
+        pCam0->setParameter(CameraParam::BRIGHTNESS, val0,
+                            [&result, &val1](auto status, auto effectiveValue) {
+                                result = status;
+                                val1 = effectiveValue;
+                            });
+        ASSERT_TRUE(result == EvsResult::OK ||
+                    result == EvsResult::INVALID_ARG);
+
+        // Verify a change notification
+        if (result == EvsResult::OK) {
+            bool timeout =
+                frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_FALSE(timeout) << "Expected event does not arrive";
+            ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
+                      InfoEventType::PARAMETER_CHANGED);
+            ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                      CameraParam::BRIGHTNESS);
+            ASSERT_EQ(val1,
+                      static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+        // Shut down the streamer
+        frameHandler0->shutdown();
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam0);
+        pEnumerator->closeCamera(pCam1);
+    }
+
+    // Explicitly release the display
+    pEnumerator->closeDisplay(pDisplay);
+}
+
+
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 94ace45..24b777c 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -50,12 +50,18 @@
     VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
     if (valueToUpdate == nullptr) {
         mPropertyValues.insert({ recId, propValue });
-    } else {
-        valueToUpdate->timestamp = propValue.timestamp;
-        valueToUpdate->value = propValue.value;
-        if (updateStatus) {
-            valueToUpdate->status = propValue.status;
-        }
+        return true;
+    }
+
+    // propValue is outdated and drops it.
+    if (valueToUpdate->timestamp > propValue.timestamp) {
+        return false;
+    }
+    // update the propertyValue.
+    valueToUpdate->timestamp = propValue.timestamp;
+    valueToUpdate->value = propValue.value;
+    if (updateStatus) {
+        valueToUpdate->status = propValue.status;
     }
     return true;
 }
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 8a008d3..4a42d79 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
@@ -85,6 +85,12 @@
     0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 
 /**
+ * This property is used for test purpose. End to end tests use this property to test set and get
+ * method for MIXED type properties.
+ */
+const int32_t kMixedTypePropertyForTest =
+        0x1111 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
  * FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty.
  * All those commands can be send independently with each other. And each will override the one sent
  * previously.
@@ -592,6 +598,14 @@
 
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::TURN_SIGNAL_STATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleTurnSignal::NONE)}}},
+
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::IGNITION_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -625,6 +639,14 @@
                         },
         },
 
+        {.config = {.prop = kMixedTypePropertyForTest,
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}},
+         .initialValue = {.stringValue = "MIXED property",
+                          .int32Values = {1 /* indicate TRUE boolean value */, 2, 3},
+                          .floatValues = {4.5f}}},
+
         {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
                     .access = VehiclePropertyAccess::READ_WRITE,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
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 ba81a52..b4f1f07 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
@@ -455,7 +455,7 @@
 
     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
     if (updatedPropValue) {
-        updatedPropValue->timestamp = elapsedRealtimeNano();
+        updatedPropValue->timestamp = value.timestamp;
         updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
         mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
         auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 955283e..8c84c0a 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -35,6 +35,21 @@
     /**
      * Any combination of scalar or vector types. The exact format must be
      * provided in the description of the property.
+     *
+     * For vendor MIXED type properties, configArray needs to be formatted in this
+     * structure.
+     * configArray[0], 1 indicates the property has a String value
+     * configArray[1], 1 indicates the property has a Boolean value .
+     * configArray[2], 1 indicates the property has an Integer value.
+     * configArray[3], the number indicates the size of Integer[] in the property.
+     * configArray[4], 1 indicates the property has a Long value.
+     * configArray[5], the number indicates the size of Long[] in the property.
+     * configArray[6], 1 indicates the property has a Float value.
+     * configArray[7], the number indicates the size of Float[] in the property.
+     * configArray[8], the number indicates the size of byte[] in the property.
+     * For example:
+     * {@code configArray = {1, 1, 1, 3, 0, 0, 0, 0, 0}} indicates the property has
+     * a String value, a Boolean value, an Integer value and an array with 3 integers.
      */
     MIXED           = 0x00e00000,
 
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 3e5c6d7..f4390b2 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -21,6 +21,7 @@
         "libcamera_metadata",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "libexif",
     ],
     include_dirs: ["system/media/private/camera/include"],
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index b8c40e9..76f9778 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -27,7 +27,9 @@
 
 using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
 using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
+using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
 using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
 
 HandleImporter::HandleImporter() : mInitialized(false) {}
 
@@ -36,6 +38,12 @@
         return;
     }
 
+    mMapperV4 = IMapperV4::getService();
+    if (mMapperV4 != nullptr) {
+        mInitialized = true;
+        return;
+    }
+
     mMapperV3 = IMapperV3::getService();
     if (mMapperV3 != nullptr) {
         mInitialized = true;
@@ -53,6 +61,7 @@
 }
 
 void HandleImporter::cleanup() {
+    mMapperV4.clear();
     mMapperV3.clear();
     mMapperV2.clear();
     mInitialized = false;
@@ -151,6 +160,10 @@
         initializeLocked();
     }
 
+    if (mMapperV4 != nullptr) {
+        return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
+    }
+
     if (mMapperV3 != nullptr) {
         return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
     }
@@ -159,7 +172,7 @@
         return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
     }
 
-    ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
     return false;
 }
 
@@ -169,12 +182,17 @@
     }
 
     Mutex::Autolock lock(mLock);
-    if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
         return;
     }
 
-    if (mMapperV3 != nullptr) {
+    if (mMapperV4 != nullptr) {
+        auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
+    } else if (mMapperV3 != nullptr) {
         auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
         if (!ret.isOk()) {
             ALOGE("%s: mapper freeBuffer failed: %s",
@@ -222,14 +240,27 @@
         initializeLocked();
     }
 
-    if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
         return ret;
     }
 
     hidl_handle acquireFenceHandle;
     auto buffer = const_cast<native_handle_t*>(buf);
-    if (mMapperV3 != nullptr) {
+    if (mMapperV4 != nullptr) {
+        IMapperV4::Rect accessRegion{0, 0, static_cast<int>(size), 1};
+        // No need to use bytesPerPixel and bytesPerStride because we are using
+        // an 1-D buffer and accressRegion.
+        mMapperV4->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
+                            const auto& /*bytesPerStride*/) {
+                            if (tmpError == MapperErrorV4::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
+    } else if (mMapperV3 != nullptr) {
         IMapperV3::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
         // No need to use bytesPerPixel and bytesPerStride because we are using
         // an 1-D buffer and accressRegion.
@@ -269,6 +300,10 @@
         initializeLocked();
     }
 
+    if (mMapperV4 != nullptr) {
+        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
+    }
+
     if (mMapperV3 != nullptr) {
         return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
                 mMapperV3, buf, cpuUsage, accessRegion);
@@ -279,11 +314,14 @@
                 mMapperV2, buf, cpuUsage, accessRegion);
     }
 
-    ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
     return {};
 }
 
 int HandleImporter::unlock(buffer_handle_t& buf) {
+    if (mMapperV4 != nullptr) {
+        return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
+    }
     if (mMapperV3 != nullptr) {
         return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
     }
@@ -291,7 +329,7 @@
         return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
     }
 
-    ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
     return -1;
 }
 
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index a93d455..fc2bbd1 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -17,10 +17,11 @@
 #ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 #define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 
-#include <utils/Mutex.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <cutils/native_handle.h>
+#include <utils/Mutex.h>
 
 using android::hardware::graphics::mapper::V2_0::IMapper;
 using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
@@ -70,6 +71,7 @@
     bool mInitialized;
     sp<IMapper> mMapperV2;
     sp<graphics::mapper::V3_0::IMapper> mMapperV3;
+    sp<graphics::mapper::V4_0::IMapper> mMapperV4;
 };
 
 } // namespace helper
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index aa3b941..c3518d3 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -16,6 +16,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hardware.graphics.common@1.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index edb008e..edc2988 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -14,6 +14,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
         "libhardware",
         "libcamera_metadata",
diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp
index 39d379d..f3c2e0e 100644
--- a/camera/device/3.3/default/Android.bp
+++ b/camera/device/3.3/default/Android.bp
@@ -16,6 +16,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
         "libhardware",
         "libcamera_metadata",
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index c22b13c..8e699d8 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -49,6 +49,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
         "libhardware",
         "libcamera_metadata",
@@ -86,6 +87,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
         "libhardware",
         "libcamera_metadata",
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 26b3b67..dde585e 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -50,6 +50,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
         "libhardware",
         "libcamera_metadata",
@@ -83,7 +84,8 @@
         "android.hardware.camera.device@3.5",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
-	"android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
         "libhardware",
         "libcamera_metadata",
diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
new file mode 100644
index 0000000..4ebd069
--- /dev/null
+++ b/camera/metadata/3.5/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.metadata@3.5",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.metadata@3.2",
+        "android.hardware.camera.metadata@3.3",
+        "android.hardware.camera.metadata@3.4",
+    ],
+    gen_java: true,
+}
+
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
new file mode 100644
index 0000000..0fec947
--- /dev/null
+++ b/camera/metadata/3.5/types.hal
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.5;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+
+// No new metadata sections added in this revision
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
+
+/** android.request.availableCapabilities enumeration values added since v3.4
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+        @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index cb78fcb..313b29b 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -13,6 +13,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@1.0-impl",
@@ -52,6 +53,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@3.3-impl",
@@ -95,6 +97,8 @@
         "android.hardware.camera.provider@2.4-external",
         "android.hardware.camera.provider@2.4-legacy",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@1.0-impl",
@@ -140,6 +144,8 @@
         "android.hardware.camera.device@3.5",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libbinder",
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2c3ed37..5fe7b19 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -43,9 +43,11 @@
         "android.hardware.camera.provider@2.5",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "libgrallocusage",
         "libhidlmemory",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index e0d41ba..67d5bbe 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -55,9 +55,11 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/2.0/types.h>
 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMapper.h>
 #include <android/hidl/memory/1.0/IMemory.h>
@@ -6213,13 +6215,44 @@
         android::hardware::graphics::allocator::V2_0::IAllocator::getService();
     sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocatorV3 =
         android::hardware::graphics::allocator::V3_0::IAllocator::getService();
+    sp<android::hardware::graphics::allocator::V4_0::IAllocator> allocatorV4 =
+            android::hardware::graphics::allocator::V4_0::IAllocator::getService();
 
+    sp<android::hardware::graphics::mapper::V4_0::IMapper> mapperV4 =
+            android::hardware::graphics::mapper::V4_0::IMapper::getService();
     sp<android::hardware::graphics::mapper::V3_0::IMapper> mapperV3 =
         android::hardware::graphics::mapper::V3_0::IMapper::getService();
     sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
         android::hardware::graphics::mapper::V2_0::IMapper::getService();
     ::android::hardware::hidl_vec<uint32_t> descriptor;
-    if (mapperV3 != nullptr && allocatorV3 != nullptr) {
+    if (mapperV4 != nullptr && allocatorV4 != nullptr) {
+        android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo descriptorInfo{};
+        descriptorInfo.width = width;
+        descriptorInfo.height = height;
+        descriptorInfo.layerCount = 1;
+        descriptorInfo.format =
+                static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+        descriptorInfo.usage = usage;
+
+        auto ret = mapperV4->createDescriptor(
+                descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V4_0::Error err,
+                                              ::android::hardware::hidl_vec<uint32_t> desc) {
+                    ASSERT_EQ(err, android::hardware::graphics::mapper::V4_0::Error::NONE);
+                    descriptor = desc;
+                });
+        ASSERT_TRUE(ret.isOk());
+
+        ret = allocatorV4->allocate(
+                descriptor, 1u,
+                [&](android::hardware::graphics::mapper::V4_0::Error err, uint32_t /*stride*/,
+                    const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>&
+                            buffers) {
+                    ASSERT_EQ(android::hardware::graphics::mapper::V4_0::Error::NONE, err);
+                    ASSERT_EQ(buffers.size(), 1u);
+                    *buffer_handle = buffers[0];
+                });
+        ASSERT_TRUE(ret.isOk());
+    } else if (mapperV3 != nullptr && allocatorV3 != nullptr) {
         android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {};
         descriptorInfo.width = width;
         descriptorInfo.height = height;
diff --git a/camera/provider/2.5/default/service.cpp b/camera/provider/2.5/default/service.cpp
index 604215d..ec30cbc 100644
--- a/camera/provider/2.5/default/service.cpp
+++ b/camera/provider/2.5/default/service.cpp
@@ -49,8 +49,8 @@
 
     status_t status;
     if (kLazyService) {
-        auto serviceRegistrar = std::make_shared<::android::hardware::LazyServiceRegistrar>();
-        status = serviceRegistrar->registerService(provider, "legacy/0");
+        auto serviceRegistrar = ::android::hardware::LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(provider, "legacy/0");
     } else {
         status = provider->registerAsService("legacy/0");
     }
diff --git a/cas/1.0/default/service.cpp b/cas/1.0/default/service.cpp
index 516acfb..754c0c5 100644
--- a/cas/1.0/default/service.cpp
+++ b/cas/1.0/default/service.cpp
@@ -46,8 +46,8 @@
     android::sp<IMediaCasService> service = new MediaCasService();
     android::status_t status;
     if (kLazyService) {
-        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
-        status = serviceRegistrar->registerService(service);
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
     } else {
         status = service->registerAsService();
     }
diff --git a/cas/1.1/default/service.cpp b/cas/1.1/default/service.cpp
index 9625303..bf0e159 100644
--- a/cas/1.1/default/service.cpp
+++ b/cas/1.1/default/service.cpp
@@ -46,8 +46,8 @@
     android::sp<IMediaCasService> service = new MediaCasService();
     android::status_t status;
     if (kLazyService) {
-        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
-        status = serviceRegistrar->registerService(service);
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
     } else {
         status = service->registerAsService();
     }
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp
index 63accff..c4feae5 100644
--- a/graphics/composer/2.1/default/Android.bp
+++ b/graphics/composer/2.1/default/Android.bp
@@ -9,8 +9,7 @@
     ],
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
         "libbase",
         "libcutils",
         "libfmq",
diff --git a/graphics/composer/2.1/utils/hal/Android.bp b/graphics/composer/2.1/utils/hal/Android.bp
index 7a501fc..ea3666d 100644
--- a/graphics/composer/2.1/utils/hal/Android.bp
+++ b/graphics/composer/2.1/utils/hal/Android.bp
@@ -19,14 +19,12 @@
     vendor_available: true,
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
         "libhardware", // TODO remove hwcomposer2.h dependency
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
         "libhardware",
     ],
     header_libs: [
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
index 095189f..47ead41 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
@@ -27,7 +27,7 @@
 #include <android/hardware/graphics/composer/2.1/IComposerClient.h>
 #include <composer-hal/2.1/ComposerCommandEngine.h>
 #include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
 #include <log/log.h>
 
 namespace android {
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
index d87110a..53b9202 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
@@ -24,7 +24,7 @@
 
 #include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
 #include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
 // TODO remove hwcomposer_defs.h dependency
 #include <hardware/hwcomposer_defs.h>
 #include <log/log.h>
@@ -195,7 +195,7 @@
         bool closeFence = true;
 
         const native_handle_t* clientTarget;
-        ComposerResources::ReplacedBufferHandle replacedClientTarget;
+        ComposerResources::ReplacedHandle replacedClientTarget(true);
         auto err = mResources->getDisplayClientTarget(mCurrentDisplay, slot, useCache, rawHandle,
                                                       &clientTarget, &replacedClientTarget);
         if (err == Error::NONE) {
@@ -226,7 +226,7 @@
         bool closeFence = true;
 
         const native_handle_t* outputBuffer;
-        ComposerResources::ReplacedBufferHandle replacedOutputBuffer;
+        ComposerResources::ReplacedHandle replacedOutputBuffer(true);
         auto err = mResources->getDisplayOutputBuffer(mCurrentDisplay, slot, useCache, rawhandle,
                                                       &outputBuffer, &replacedOutputBuffer);
         if (err == Error::NONE) {
@@ -369,7 +369,7 @@
         bool closeFence = true;
 
         const native_handle_t* buffer;
-        ComposerResources::ReplacedBufferHandle replacedBuffer;
+        ComposerResources::ReplacedHandle replacedBuffer(true);
         auto err = mResources->getLayerBuffer(mCurrentDisplay, mCurrentLayer, slot, useCache,
                                               rawHandle, &buffer, &replacedBuffer);
         if (err == Error::NONE) {
@@ -489,7 +489,7 @@
         auto rawHandle = readHandle();
 
         const native_handle_t* stream;
-        ComposerResources::ReplacedStreamHandle replacedStream;
+        ComposerResources::ReplacedHandle replacedStream(false);
         auto err = mResources->getLayerSidebandStream(mCurrentDisplay, mCurrentLayer, rawHandle,
                                                       &stream, &replacedStream);
         if (err == Error::NONE) {
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
deleted file mode 100644
index 18d184e..0000000
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * 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 "ComposerResources.h included without LOG_TAG"
-#endif
-
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace hal {
-
-// wrapper for IMapper to import buffers and sideband streams
-class ComposerHandleImporter {
-   public:
-    bool init() {
-        mMapper3 = mapper::V3_0::IMapper::getService();
-        if (mMapper3) {
-            return true;
-        }
-        ALOGD_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
-
-        mMapper2 = mapper::V2_0::IMapper::getService();
-        ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
-
-        return mMapper2 != nullptr;
-    }
-
-    Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) {
-        if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
-            *outBufferHandle = nullptr;
-            return Error::NONE;
-        }
-
-        const native_handle_t* bufferHandle;
-        if (mMapper2) {
-            mapper::V2_0::Error error;
-            mMapper2->importBuffer(
-                rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
-                    error = tmpError;
-                    bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
-                });
-            if (error != mapper::V2_0::Error::NONE) {
-                return Error::NO_RESOURCES;
-            }
-        }
-        if (mMapper3) {
-            mapper::V3_0::Error error;
-            mMapper3->importBuffer(
-                rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
-                    error = tmpError;
-                    bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
-                });
-            if (error != mapper::V3_0::Error::NONE) {
-                return Error::NO_RESOURCES;
-            }
-        }
-
-        *outBufferHandle = bufferHandle;
-        return Error::NONE;
-    }
-
-    void freeBuffer(const native_handle_t* bufferHandle) {
-        if (bufferHandle) {
-            if (mMapper2) {
-                mMapper2->freeBuffer(
-                    static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
-            } else if (mMapper3) {
-                mMapper3->freeBuffer(
-                    static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
-            }
-        }
-    }
-
-    Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle) {
-        const native_handle_t* streamHandle = nullptr;
-        if (rawHandle) {
-            streamHandle = native_handle_clone(rawHandle);
-            if (!streamHandle) {
-                return Error::NO_RESOURCES;
-            }
-        }
-
-        *outStreamHandle = streamHandle;
-        return Error::NONE;
-    }
-
-    void freeStream(const native_handle_t* streamHandle) {
-        if (streamHandle) {
-            native_handle_close(streamHandle);
-            native_handle_delete(const_cast<native_handle_t*>(streamHandle));
-        }
-    }
-
-   private:
-    sp<mapper::V2_0::IMapper> mMapper2;
-    sp<mapper::V3_0::IMapper> mMapper3;
-};
-
-class ComposerHandleCache {
-   public:
-    enum class HandleType {
-        INVALID,
-        BUFFER,
-        STREAM,
-    };
-
-    ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize)
-        : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
-
-    // must be initialized later with initCache
-    ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
-
-    ~ComposerHandleCache() {
-        switch (mHandleType) {
-            case HandleType::BUFFER:
-                for (auto handle : mHandles) {
-                    mImporter.freeBuffer(handle);
-                }
-                break;
-            case HandleType::STREAM:
-                for (auto handle : mHandles) {
-                    mImporter.freeStream(handle);
-                }
-                break;
-            default:
-                break;
-        }
-    }
-
-    ComposerHandleCache(const ComposerHandleCache&) = delete;
-    ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
-
-    bool initCache(HandleType type, uint32_t cacheSize) {
-        // already initialized
-        if (mHandleType != HandleType::INVALID) {
-            return false;
-        }
-
-        mHandleType = type;
-        mHandles.resize(cacheSize, nullptr);
-
-        return true;
-    }
-
-    Error lookupCache(uint32_t slot, const native_handle_t** outHandle) {
-        if (slot >= 0 && slot < mHandles.size()) {
-            *outHandle = mHandles[slot];
-            return Error::NONE;
-        } else {
-            return Error::BAD_PARAMETER;
-        }
-    }
-
-    Error updateCache(uint32_t slot, const native_handle_t* handle,
-                      const native_handle** outReplacedHandle) {
-        if (slot >= 0 && slot < mHandles.size()) {
-            auto& cachedHandle = mHandles[slot];
-            *outReplacedHandle = cachedHandle;
-            cachedHandle = handle;
-            return Error::NONE;
-        } else {
-            return Error::BAD_PARAMETER;
-        }
-    }
-
-    // when fromCache is true, look up in the cache; otherwise, update the cache
-    Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                    const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
-        if (fromCache) {
-            *outReplacedHandle = nullptr;
-            return lookupCache(slot, outHandle);
-        } else {
-            *outHandle = inHandle;
-            return updateCache(slot, inHandle, outReplacedHandle);
-        }
-    }
-
-   private:
-    ComposerHandleImporter& mImporter;
-    HandleType mHandleType = HandleType::INVALID;
-    std::vector<const native_handle_t*> mHandles;
-};
-
-// layer resource
-class ComposerLayerResource {
-   public:
-    ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize)
-        : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
-          mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
-
-    virtual ~ComposerLayerResource() = default;
-
-    Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                    const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
-        return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
-    }
-
-    Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                            const native_handle_t** outHandle,
-                            const native_handle** outReplacedHandle) {
-        return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle,
-                                              outReplacedHandle);
-    }
-
-   protected:
-    ComposerHandleCache mBufferCache;
-    ComposerHandleCache mSidebandStreamCache;
-};
-
-// display resource
-class ComposerDisplayResource {
-   public:
-    enum class DisplayType {
-        PHYSICAL,
-        VIRTUAL,
-    };
-
-    virtual ~ComposerDisplayResource() = default;
-
-    ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
-                            uint32_t outputBufferCacheSize)
-        : mType(type),
-          mClientTargetCache(importer),
-          mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER,
-                             outputBufferCacheSize),
-          mMustValidate(true) {}
-
-    bool initClientTargetCache(uint32_t cacheSize) {
-        return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
-    }
-
-    bool isVirtual() const { return mType == DisplayType::VIRTUAL; }
-
-    Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                          const native_handle_t** outHandle,
-                          const native_handle** outReplacedHandle) {
-        return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle,
-                                            outReplacedHandle);
-    }
-
-    Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                          const native_handle_t** outHandle,
-                          const native_handle** outReplacedHandle) {
-        return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
-                                            outReplacedHandle);
-    }
-
-    bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource) {
-        auto result = mLayerResources.emplace(layer, std::move(layerResource));
-        return result.second;
-    }
-
-    bool removeLayer(Layer layer) { return mLayerResources.erase(layer) > 0; }
-
-    ComposerLayerResource* findLayerResource(Layer layer) {
-        auto layerIter = mLayerResources.find(layer);
-        if (layerIter == mLayerResources.end()) {
-            return nullptr;
-        }
-
-        return layerIter->second.get();
-    }
-
-    std::vector<Layer> getLayers() const {
-        std::vector<Layer> layers;
-        layers.reserve(mLayerResources.size());
-        for (const auto& layerKey : mLayerResources) {
-            layers.push_back(layerKey.first);
-        }
-        return layers;
-    }
-
-    void setMustValidateState(bool mustValidate) { mMustValidate = mustValidate; }
-
-    bool mustValidate() const { return mMustValidate; }
-
-   protected:
-    const DisplayType mType;
-    ComposerHandleCache mClientTargetCache;
-    ComposerHandleCache mOutputBufferCache;
-    bool mMustValidate;
-
-    std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
-};
-
-class ComposerResources {
-   private:
-    template <bool isBuffer>
-    class ReplacedHandle;
-
-   public:
-    static std::unique_ptr<ComposerResources> create() {
-        auto resources = std::make_unique<ComposerResources>();
-        return resources->init() ? std::move(resources) : nullptr;
-    }
-
-    ComposerResources() = default;
-    virtual ~ComposerResources() = default;
-
-    bool init() { return mImporter.init(); }
-
-    using RemoveDisplay =
-        std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
-    void clear(RemoveDisplay removeDisplay) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        for (const auto& displayKey : mDisplayResources) {
-            Display display = displayKey.first;
-            const ComposerDisplayResource& displayResource = *displayKey.second;
-            removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
-        }
-        mDisplayResources.clear();
-    }
-
-    Error addPhysicalDisplay(Display display) {
-        auto displayResource =
-            createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto result = mDisplayResources.emplace(display, std::move(displayResource));
-        return result.second ? Error::NONE : Error::BAD_DISPLAY;
-    }
-
-    Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
-        auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
-                                                     outputBufferCacheSize);
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto result = mDisplayResources.emplace(display, std::move(displayResource));
-        return result.second ? Error::NONE : Error::BAD_DISPLAY;
-    }
-
-    Error removeDisplay(Display display) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
-    }
-
-    Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        if (!displayResource) {
-            return Error::BAD_DISPLAY;
-        }
-
-        return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
-                                                                             : Error::BAD_PARAMETER;
-    }
-
-    Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
-        auto layerResource = createLayerResource(bufferCacheSize);
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        if (!displayResource) {
-            return Error::BAD_DISPLAY;
-        }
-
-        return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
-                                                                          : Error::BAD_LAYER;
-    }
-
-    Error removeLayer(Display display, Layer layer) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        if (!displayResource) {
-            return Error::BAD_DISPLAY;
-        }
-
-        return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
-    }
-
-    using ReplacedBufferHandle = ReplacedHandle<true>;
-    using ReplacedStreamHandle = ReplacedHandle<false>;
-
-    Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
-                                 const native_handle_t* rawHandle,
-                                 const native_handle_t** outBufferHandle,
-                                 ReplacedBufferHandle* outReplacedBuffer) {
-        return getHandle<Cache::CLIENT_TARGET>(display, 0, slot, fromCache, rawHandle,
-                                               outBufferHandle, outReplacedBuffer);
-    }
-
-    Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
-                                 const native_handle_t* rawHandle,
-                                 const native_handle_t** outBufferHandle,
-                                 ReplacedBufferHandle* outReplacedBuffer) {
-        return getHandle<Cache::OUTPUT_BUFFER>(display, 0, slot, fromCache, rawHandle,
-                                               outBufferHandle, outReplacedBuffer);
-    }
-
-    Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
-                         const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
-                         ReplacedBufferHandle* outReplacedBuffer) {
-        return getHandle<Cache::LAYER_BUFFER>(display, layer, slot, fromCache, rawHandle,
-                                              outBufferHandle, outReplacedBuffer);
-    }
-
-    Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
-                                 const native_handle_t** outStreamHandle,
-                                 ReplacedStreamHandle* outReplacedStream) {
-        return getHandle<Cache::LAYER_SIDEBAND_STREAM>(display, layer, 0, false, rawHandle,
-                                                       outStreamHandle, outReplacedStream);
-    }
-
-    void setDisplayMustValidateState(Display display, bool mustValidate) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto* displayResource = findDisplayResourceLocked(display);
-        if (displayResource) {
-            displayResource->setMustValidateState(mustValidate);
-        }
-    }
-
-    bool mustValidateDisplay(Display display) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto* displayResource = findDisplayResourceLocked(display);
-        if (displayResource) {
-            return displayResource->mustValidate();
-        }
-        return false;
-    }
-
-   protected:
-    virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
-        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
-        return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
-    }
-
-    virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize) {
-        return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
-    }
-
-    ComposerDisplayResource* findDisplayResourceLocked(Display display) {
-        auto iter = mDisplayResources.find(display);
-        if (iter == mDisplayResources.end()) {
-            return nullptr;
-        }
-        return iter->second.get();
-    }
-
-    ComposerHandleImporter mImporter;
-
-    std::mutex mDisplayResourcesMutex;
-    std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
-
-   private:
-    enum class Cache {
-        CLIENT_TARGET,
-        OUTPUT_BUFFER,
-        LAYER_BUFFER,
-        LAYER_SIDEBAND_STREAM,
-    };
-
-    // When a buffer in the cache is replaced by a new one, we must keep it
-    // alive until it has been replaced in ComposerHal.
-    template <bool isBuffer>
-    class ReplacedHandle {
-       public:
-        ReplacedHandle() = default;
-        ReplacedHandle(const ReplacedHandle&) = delete;
-        ReplacedHandle& operator=(const ReplacedHandle&) = delete;
-
-        ~ReplacedHandle() { reset(); }
-
-        void reset(ComposerHandleImporter* importer = nullptr,
-                   const native_handle_t* handle = nullptr) {
-            if (mHandle) {
-                if (isBuffer) {
-                    mImporter->freeBuffer(mHandle);
-                } else {
-                    mImporter->freeStream(mHandle);
-                }
-            }
-
-            mImporter = importer;
-            mHandle = handle;
-        }
-
-       private:
-        ComposerHandleImporter* mImporter = nullptr;
-        const native_handle_t* mHandle = nullptr;
-    };
-
-    template <Cache cache, bool isBuffer>
-    Error getHandle(Display display, Layer layer, uint32_t slot, bool fromCache,
-                    const native_handle_t* rawHandle, const native_handle_t** outHandle,
-                    ReplacedHandle<isBuffer>* outReplacedHandle) {
-        Error error;
-
-        // import the raw handle (or ignore raw handle when fromCache is true)
-        const native_handle_t* importedHandle = nullptr;
-        if (!fromCache) {
-            error = (isBuffer) ? mImporter.importBuffer(rawHandle, &importedHandle)
-                               : mImporter.importStream(rawHandle, &importedHandle);
-            if (error != Error::NONE) {
-                return error;
-            }
-        }
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-
-        // find display/layer resource
-        const bool needLayerResource =
-            (cache == Cache::LAYER_BUFFER || cache == Cache::LAYER_SIDEBAND_STREAM);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        ComposerLayerResource* layerResource = (displayResource && needLayerResource)
-                                                   ? displayResource->findLayerResource(layer)
-                                                   : nullptr;
-
-        // lookup or update cache
-        const native_handle_t* replacedHandle = nullptr;
-        if (displayResource && (!needLayerResource || layerResource)) {
-            switch (cache) {
-                case Cache::CLIENT_TARGET:
-                    error = displayResource->getClientTarget(slot, fromCache, importedHandle,
-                                                             outHandle, &replacedHandle);
-                    break;
-                case Cache::OUTPUT_BUFFER:
-                    error = displayResource->getOutputBuffer(slot, fromCache, importedHandle,
-                                                             outHandle, &replacedHandle);
-                    break;
-                case Cache::LAYER_BUFFER:
-                    error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
-                                                     &replacedHandle);
-                    break;
-                case Cache::LAYER_SIDEBAND_STREAM:
-                    error = layerResource->getSidebandStream(slot, fromCache, importedHandle,
-                                                             outHandle, &replacedHandle);
-                    break;
-                default:
-                    error = Error::BAD_PARAMETER;
-                    break;
-            }
-
-            if (error != Error::NONE) {
-                ALOGW("invalid cache %d slot %d", int(cache), int(slot));
-            }
-        } else if (!displayResource) {
-            error = Error::BAD_DISPLAY;
-        } else {
-            error = Error::BAD_LAYER;
-        }
-
-        // clean up on errors
-        if (error != Error::NONE) {
-            if (!fromCache) {
-                if (isBuffer) {
-                    mImporter.freeBuffer(importedHandle);
-                } else {
-                    mImporter.freeStream(importedHandle);
-                }
-            }
-            return error;
-        }
-
-        outReplacedHandle->reset(&mImporter, replacedHandle);
-
-        return Error::NONE;
-    }
-};
-
-}  // namespace hal
-}  // namespace V2_1
-}  // namespace composer
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp
new file mode 100644
index 0000000..ed827fe
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "android.hardware.graphics.composer@2.1-resources",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "libcutils",
+        "libhardware", // TODO remove hwcomposer2.h dependency
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "ComposerResources.cpp",
+    ],
+}
diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..21f6035
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ComposerResources"
+
+#include "composer-resources/2.1/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+bool ComposerHandleImporter::init() {
+    mMapper4 = mapper::V4_0::IMapper::getService();
+    if (mMapper4) {
+        return true;
+    }
+    ALOGI_IF(!mMapper4, "failed to get mapper 4.0 service, falling back to mapper 3.0");
+
+    mMapper3 = mapper::V3_0::IMapper::getService();
+    if (mMapper3) {
+        return true;
+    }
+    ALOGI_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
+
+    mMapper2 = mapper::V2_0::IMapper::getService();
+    ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
+
+    return mMapper2 != nullptr;
+}
+
+Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle,
+                                           const native_handle_t** outBufferHandle) {
+    if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
+        *outBufferHandle = nullptr;
+        return Error::NONE;
+    }
+
+    const native_handle_t* bufferHandle;
+    if (mMapper2) {
+        mapper::V2_0::Error error;
+        mMapper2->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+            error = tmpError;
+            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+        });
+        if (error != mapper::V2_0::Error::NONE) {
+            return Error::NO_RESOURCES;
+        }
+    }
+    if (mMapper3) {
+        mapper::V3_0::Error error;
+        mMapper3->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+            error = tmpError;
+            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+        });
+        if (error != mapper::V3_0::Error::NONE) {
+            return Error::NO_RESOURCES;
+        }
+    }
+    if (mMapper4) {
+        mapper::V4_0::Error error;
+        mMapper4->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+            error = tmpError;
+            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+        });
+        if (error != mapper::V4_0::Error::NONE) {
+            return Error::NO_RESOURCES;
+        }
+    }
+
+    *outBufferHandle = bufferHandle;
+    return Error::NONE;
+}
+
+void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) {
+    if (bufferHandle) {
+        if (mMapper2) {
+            mMapper2->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+        } else if (mMapper3) {
+            mMapper3->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+        } else if (mMapper4) {
+            mMapper4->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+        }
+    }
+}
+
+Error ComposerHandleImporter::importStream(const native_handle_t* rawHandle,
+                                           const native_handle_t** outStreamHandle) {
+    const native_handle_t* streamHandle = nullptr;
+    if (rawHandle) {
+        streamHandle = native_handle_clone(rawHandle);
+        if (!streamHandle) {
+            return Error::NO_RESOURCES;
+        }
+    }
+
+    *outStreamHandle = streamHandle;
+    return Error::NONE;
+}
+
+void ComposerHandleImporter::freeStream(const native_handle_t* streamHandle) {
+    if (streamHandle) {
+        native_handle_close(streamHandle);
+        native_handle_delete(const_cast<native_handle_t*>(streamHandle));
+    }
+}
+
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer, HandleType type,
+                                         uint32_t cacheSize)
+    : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
+
+// must be initialized later with initCache
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
+
+ComposerHandleCache::~ComposerHandleCache() {
+    switch (mHandleType) {
+        case HandleType::BUFFER:
+            for (auto handle : mHandles) {
+                mImporter.freeBuffer(handle);
+            }
+            break;
+        case HandleType::STREAM:
+            for (auto handle : mHandles) {
+                mImporter.freeStream(handle);
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+bool ComposerHandleCache::initCache(HandleType type, uint32_t cacheSize) {
+    // already initialized
+    if (mHandleType != HandleType::INVALID) {
+        return false;
+    }
+
+    mHandleType = type;
+    mHandles.resize(cacheSize, nullptr);
+
+    return true;
+}
+
+Error ComposerHandleCache::lookupCache(uint32_t slot, const native_handle_t** outHandle) {
+    if (slot >= 0 && slot < mHandles.size()) {
+        *outHandle = mHandles[slot];
+        return Error::NONE;
+    } else {
+        return Error::BAD_PARAMETER;
+    }
+}
+
+Error ComposerHandleCache::updateCache(uint32_t slot, const native_handle_t* handle,
+                                       const native_handle** outReplacedHandle) {
+    if (slot >= 0 && slot < mHandles.size()) {
+        auto& cachedHandle = mHandles[slot];
+        *outReplacedHandle = cachedHandle;
+        cachedHandle = handle;
+        return Error::NONE;
+    } else {
+        return Error::BAD_PARAMETER;
+    }
+}
+
+// when fromCache is true, look up in the cache; otherwise, update the cache
+Error ComposerHandleCache::getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                                     const native_handle_t** outHandle,
+                                     const native_handle** outReplacedHandle) {
+    if (fromCache) {
+        *outReplacedHandle = nullptr;
+        return lookupCache(slot, outHandle);
+    } else {
+        *outHandle = inHandle;
+        return updateCache(slot, inHandle, outReplacedHandle);
+    }
+}
+
+ComposerLayerResource::ComposerLayerResource(ComposerHandleImporter& importer,
+                                             uint32_t bufferCacheSize)
+    : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
+      mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
+
+Error ComposerLayerResource::getBuffer(uint32_t slot, bool fromCache,
+                                       const native_handle_t* inHandle,
+                                       const native_handle_t** outHandle,
+                                       const native_handle** outReplacedHandle) {
+    return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerLayerResource::getSidebandStream(uint32_t slot, bool fromCache,
+                                               const native_handle_t* inHandle,
+                                               const native_handle_t** outHandle,
+                                               const native_handle** outReplacedHandle) {
+    return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+ComposerDisplayResource::ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+                                                 uint32_t outputBufferCacheSize)
+    : mType(type),
+      mClientTargetCache(importer),
+      mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, outputBufferCacheSize),
+      mMustValidate(true) {}
+
+bool ComposerDisplayResource::initClientTargetCache(uint32_t cacheSize) {
+    return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
+}
+
+bool ComposerDisplayResource::isVirtual() const {
+    return mType == DisplayType::VIRTUAL;
+}
+
+Error ComposerDisplayResource::getClientTarget(uint32_t slot, bool fromCache,
+                                               const native_handle_t* inHandle,
+                                               const native_handle_t** outHandle,
+                                               const native_handle** outReplacedHandle) {
+    return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerDisplayResource::getOutputBuffer(uint32_t slot, bool fromCache,
+                                               const native_handle_t* inHandle,
+                                               const native_handle_t** outHandle,
+                                               const native_handle** outReplacedHandle) {
+    return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+bool ComposerDisplayResource::addLayer(Layer layer,
+                                       std::unique_ptr<ComposerLayerResource> layerResource) {
+    auto result = mLayerResources.emplace(layer, std::move(layerResource));
+    return result.second;
+}
+
+bool ComposerDisplayResource::removeLayer(Layer layer) {
+    return mLayerResources.erase(layer) > 0;
+}
+
+ComposerLayerResource* ComposerDisplayResource::findLayerResource(Layer layer) {
+    auto layerIter = mLayerResources.find(layer);
+    if (layerIter == mLayerResources.end()) {
+        return nullptr;
+    }
+
+    return layerIter->second.get();
+}
+
+std::vector<Layer> ComposerDisplayResource::getLayers() const {
+    std::vector<Layer> layers;
+    layers.reserve(mLayerResources.size());
+    for (const auto& layerKey : mLayerResources) {
+        layers.push_back(layerKey.first);
+    }
+    return layers;
+}
+
+void ComposerDisplayResource::setMustValidateState(bool mustValidate) {
+    mMustValidate = mustValidate;
+}
+
+bool ComposerDisplayResource::mustValidate() const {
+    return mMustValidate;
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+    auto resources = std::make_unique<ComposerResources>();
+    return resources->init() ? std::move(resources) : nullptr;
+}
+
+bool ComposerResources::init() {
+    return mImporter.init();
+}
+
+void ComposerResources::clear(RemoveDisplay removeDisplay) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    for (const auto& displayKey : mDisplayResources) {
+        Display display = displayKey.first;
+        const ComposerDisplayResource& displayResource = *displayKey.second;
+        removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
+    }
+    mDisplayResources.clear();
+}
+
+Error ComposerResources::addPhysicalDisplay(Display display) {
+    auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto result = mDisplayResources.emplace(display, std::move(displayResource));
+    return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
+    auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
+                                                 outputBufferCacheSize);
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto result = mDisplayResources.emplace(display, std::move(displayResource));
+    return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::removeDisplay(Display display) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::setDisplayClientTargetCacheSize(Display display,
+                                                         uint32_t clientTargetCacheSize) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    if (!displayResource) {
+        return Error::BAD_DISPLAY;
+    }
+
+    return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
+                                                                         : Error::BAD_PARAMETER;
+}
+
+Error ComposerResources::addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
+    auto layerResource = createLayerResource(bufferCacheSize);
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    if (!displayResource) {
+        return Error::BAD_DISPLAY;
+    }
+
+    return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
+                                                                      : Error::BAD_LAYER;
+}
+
+Error ComposerResources::removeLayer(Display display, Layer layer) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    if (!displayResource) {
+        return Error::BAD_DISPLAY;
+    }
+
+    return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
+}
+
+Error ComposerResources::getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+                                                const native_handle_t* rawHandle,
+                                                const native_handle_t** outBufferHandle,
+                                                ReplacedHandle* outReplacedBuffer) {
+    return getHandle(display, 0, slot, Cache::CLIENT_TARGET, fromCache, rawHandle, outBufferHandle,
+                     outReplacedBuffer);
+}
+
+Error ComposerResources::getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+                                                const native_handle_t* rawHandle,
+                                                const native_handle_t** outBufferHandle,
+                                                ReplacedHandle* outReplacedBuffer) {
+    return getHandle(display, 0, slot, Cache::OUTPUT_BUFFER, fromCache, rawHandle, outBufferHandle,
+                     outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+                                        const native_handle_t* rawHandle,
+                                        const native_handle_t** outBufferHandle,
+                                        ReplacedHandle* outReplacedBuffer) {
+    return getHandle(display, layer, slot, Cache::LAYER_BUFFER, fromCache, rawHandle,
+                     outBufferHandle, outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerSidebandStream(Display display, Layer layer,
+                                                const native_handle_t* rawHandle,
+                                                const native_handle_t** outStreamHandle,
+                                                ReplacedHandle* outReplacedStream) {
+    return getHandle(display, layer, 0, Cache::LAYER_SIDEBAND_STREAM, false, rawHandle,
+                     outStreamHandle, outReplacedStream);
+}
+
+void ComposerResources::setDisplayMustValidateState(Display display, bool mustValidate) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto* displayResource = findDisplayResourceLocked(display);
+    if (displayResource) {
+        displayResource->setMustValidateState(mustValidate);
+    }
+}
+
+bool ComposerResources::mustValidateDisplay(Display display) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto* displayResource = findDisplayResourceLocked(display);
+    if (displayResource) {
+        return displayResource->mustValidate();
+    }
+    return false;
+}
+
+std::unique_ptr<ComposerDisplayResource> ComposerResources::createDisplayResource(
+        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
+    return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+}
+
+std::unique_ptr<ComposerLayerResource> ComposerResources::createLayerResource(
+        uint32_t bufferCacheSize) {
+    return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
+}
+
+ComposerDisplayResource* ComposerResources::findDisplayResourceLocked(Display display) {
+    auto iter = mDisplayResources.find(display);
+    if (iter == mDisplayResources.end()) {
+        return nullptr;
+    }
+    return iter->second.get();
+}
+
+Error ComposerResources::getHandle(Display display, Layer layer, uint32_t slot, Cache cache,
+                                   bool fromCache, const native_handle_t* rawHandle,
+                                   const native_handle_t** outHandle,
+                                   ReplacedHandle* outReplacedHandle) {
+    Error error;
+
+    // import the raw handle (or ignore raw handle when fromCache is true)
+    const native_handle_t* importedHandle = nullptr;
+    if (!fromCache) {
+        error = (outReplacedHandle->isBuffer())
+                        ? mImporter.importBuffer(rawHandle, &importedHandle)
+                        : mImporter.importStream(rawHandle, &importedHandle);
+        if (error != Error::NONE) {
+            return error;
+        }
+    }
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+    // find display/layer resource
+    const bool needLayerResource = (cache == ComposerResources::Cache::LAYER_BUFFER ||
+                                    cache == ComposerResources::Cache::LAYER_SIDEBAND_STREAM);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    ComposerLayerResource* layerResource = (displayResource && needLayerResource)
+                                                   ? displayResource->findLayerResource(layer)
+                                                   : nullptr;
+
+    // lookup or update cache
+    const native_handle_t* replacedHandle = nullptr;
+    if (displayResource && (!needLayerResource || layerResource)) {
+        switch (cache) {
+            case ComposerResources::Cache::CLIENT_TARGET:
+                error = displayResource->getClientTarget(slot, fromCache, importedHandle, outHandle,
+                                                         &replacedHandle);
+                break;
+            case ComposerResources::Cache::OUTPUT_BUFFER:
+                error = displayResource->getOutputBuffer(slot, fromCache, importedHandle, outHandle,
+                                                         &replacedHandle);
+                break;
+            case ComposerResources::Cache::LAYER_BUFFER:
+                error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
+                                                 &replacedHandle);
+                break;
+            case ComposerResources::Cache::LAYER_SIDEBAND_STREAM:
+                error = layerResource->getSidebandStream(slot, fromCache, importedHandle, outHandle,
+                                                         &replacedHandle);
+                break;
+            default:
+                error = Error::BAD_PARAMETER;
+                break;
+        }
+
+        if (error != Error::NONE) {
+            ALOGW("invalid cache %d slot %d", int(cache), int(slot));
+        }
+    } else if (!displayResource) {
+        error = Error::BAD_DISPLAY;
+    } else {
+        error = Error::BAD_LAYER;
+    }
+
+    // clean up on errors
+    if (error != Error::NONE) {
+        if (!fromCache) {
+            if (outReplacedHandle->isBuffer()) {
+                mImporter.freeBuffer(importedHandle);
+            } else {
+                mImporter.freeStream(importedHandle);
+            }
+        }
+        return error;
+    }
+
+    outReplacedHandle->reset(&mImporter, replacedHandle);
+
+    return Error::NONE;
+}
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
new file mode 100644
index 0000000..3738278
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
@@ -0,0 +1,260 @@
+/*
+ * 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 "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/types.h>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+// wrapper for IMapper to import buffers and sideband streams
+class ComposerHandleImporter {
+  public:
+    bool init();
+
+    Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle);
+    void freeBuffer(const native_handle_t* bufferHandle);
+    Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle);
+    void freeStream(const native_handle_t* streamHandle);
+
+  private:
+    sp<mapper::V2_0::IMapper> mMapper2;
+    sp<mapper::V3_0::IMapper> mMapper3;
+    sp<mapper::V4_0::IMapper> mMapper4;
+};
+
+class ComposerHandleCache {
+  public:
+    enum class HandleType {
+        INVALID,
+        BUFFER,
+        STREAM,
+    };
+
+    ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize);
+
+    // must be initialized later with initCache
+    ComposerHandleCache(ComposerHandleImporter& importer);
+
+    ~ComposerHandleCache();
+
+    ComposerHandleCache(const ComposerHandleCache&) = delete;
+    ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
+
+    bool initCache(HandleType type, uint32_t cacheSize);
+    Error lookupCache(uint32_t slot, const native_handle_t** outHandle);
+    Error updateCache(uint32_t slot, const native_handle_t* handle,
+                      const native_handle** outReplacedHandle);
+
+    // when fromCache is true, look up in the cache; otherwise, update the cache
+    Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                    const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+
+  private:
+    ComposerHandleImporter& mImporter;
+    HandleType mHandleType = HandleType::INVALID;
+    std::vector<const native_handle_t*> mHandles;
+};
+
+// layer resource
+class ComposerLayerResource {
+  public:
+    ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize);
+
+    virtual ~ComposerLayerResource() = default;
+
+    Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                    const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+    Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                            const native_handle_t** outHandle,
+                            const native_handle** outReplacedHandle);
+
+  protected:
+    ComposerHandleCache mBufferCache;
+    ComposerHandleCache mSidebandStreamCache;
+};
+
+// display resource
+class ComposerDisplayResource {
+  public:
+    enum class DisplayType {
+        PHYSICAL,
+        VIRTUAL,
+    };
+
+    virtual ~ComposerDisplayResource() = default;
+
+    ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+                            uint32_t outputBufferCacheSize);
+
+    bool initClientTargetCache(uint32_t cacheSize);
+
+    bool isVirtual() const;
+
+    Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                          const native_handle_t** outHandle,
+                          const native_handle** outReplacedHandle);
+
+    Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                          const native_handle_t** outHandle,
+                          const native_handle** outReplacedHandle);
+
+    bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource);
+    bool removeLayer(Layer layer);
+    ComposerLayerResource* findLayerResource(Layer layer);
+    std::vector<Layer> getLayers() const;
+
+    void setMustValidateState(bool mustValidate);
+
+    bool mustValidate() const;
+
+  protected:
+    const DisplayType mType;
+    ComposerHandleCache mClientTargetCache;
+    ComposerHandleCache mOutputBufferCache;
+    bool mMustValidate;
+
+    std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
+};
+
+class ComposerResources {
+  public:
+    static std::unique_ptr<ComposerResources> create();
+
+    ComposerResources() = default;
+    virtual ~ComposerResources() = default;
+
+    bool init();
+
+    using RemoveDisplay =
+            std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
+    void clear(RemoveDisplay removeDisplay);
+
+    Error addPhysicalDisplay(Display display);
+    Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize);
+
+    Error removeDisplay(Display display);
+
+    Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize);
+
+    Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize);
+    Error removeLayer(Display display, Layer layer);
+
+    void setDisplayMustValidateState(Display display, bool mustValidate);
+
+    bool mustValidateDisplay(Display display);
+
+    // When a buffer in the cache is replaced by a new one, we must keep it
+    // alive until it has been replaced in ComposerHal.
+    class ReplacedHandle {
+      public:
+        explicit ReplacedHandle(bool isBuffer) : mIsBuffer(isBuffer) {}
+        ReplacedHandle(const ReplacedHandle&) = delete;
+        ReplacedHandle& operator=(const ReplacedHandle&) = delete;
+
+        ~ReplacedHandle() { reset(); }
+
+        bool isBuffer() { return mIsBuffer; }
+
+        void reset(ComposerHandleImporter* importer = nullptr,
+                   const native_handle_t* handle = nullptr) {
+            if (mHandle) {
+                if (mIsBuffer) {
+                    mImporter->freeBuffer(mHandle);
+                } else {
+                    mImporter->freeStream(mHandle);
+                }
+            }
+
+            mImporter = importer;
+            mHandle = handle;
+        }
+
+      private:
+        bool mIsBuffer;
+        ComposerHandleImporter* mImporter = nullptr;
+        const native_handle_t* mHandle = nullptr;
+    };
+
+    Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+                                 const native_handle_t* rawHandle,
+                                 const native_handle_t** outBufferHandle,
+                                 ReplacedHandle* outReplacedBuffer);
+
+    Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+                                 const native_handle_t* rawHandle,
+                                 const native_handle_t** outBufferHandle,
+                                 ReplacedHandle* outReplacedBuffer);
+
+    Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+                         const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
+                         ReplacedHandle* outReplacedBuffer);
+
+    Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
+                                 const native_handle_t** outStreamHandle,
+                                 ReplacedHandle* outReplacedStream);
+
+  protected:
+    virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
+            ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize);
+
+    virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize);
+
+    ComposerDisplayResource* findDisplayResourceLocked(Display display);
+
+    ComposerHandleImporter mImporter;
+
+    std::mutex mDisplayResourcesMutex;
+    std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
+
+  private:
+    enum class Cache {
+        CLIENT_TARGET,
+        OUTPUT_BUFFER,
+        LAYER_BUFFER,
+        LAYER_SIDEBAND_STREAM,
+    };
+
+    Error getHandle(Display display, Layer layer, uint32_t slot, Cache cache, bool fromCache,
+                    const native_handle_t* rawHandle, const native_handle_t** outHandle,
+                    ReplacedHandle* outReplacedHandle);
+};
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index 88b1a8b..cdc0f35 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -27,12 +27,14 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     export_static_lib_headers: [
         "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index c5d5823..a0745ce 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -317,11 +317,16 @@
 
 Gralloc::Gralloc() {
     [this] {
-        ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
                                                                        /*errOnFailure=*/false));
-        if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
-            mGralloc3 = nullptr;
-            ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+        if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
+            mGralloc4 = nullptr;
+            ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+                                                                           /*errOnFailure=*/false));
+            if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
+                mGralloc3 = nullptr;
+                ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+            }
         }
     }();
 }
@@ -329,7 +334,15 @@
 const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount,
                                          PixelFormat format, uint64_t usage, bool import,
                                          uint32_t* outStride) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        IMapper4::BufferDescriptorInfo info{};
+        info.width = width;
+        info.height = height;
+        info.layerCount = layerCount;
+        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+        info.usage = usage;
+        return mGralloc4->allocate(info, import, outStride);
+    } else if (mGralloc3) {
         IMapper3::BufferDescriptorInfo info{};
         info.width = width;
         info.height = height;
@@ -350,7 +363,17 @@
 
 void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
                     const AccessRegion& accessRegionRect, int acquireFence) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        IMapper4::Rect accessRegion;
+        accessRegion.left = accessRegionRect.left;
+        accessRegion.top = accessRegionRect.top;
+        accessRegion.width = accessRegionRect.width;
+        accessRegion.height = accessRegionRect.height;
+        int32_t bytesPerPixel;
+        int32_t bytesPerStride;
+        return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel,
+                               &bytesPerStride);
+    } else if (mGralloc3) {
         IMapper3::Rect accessRegion;
         accessRegion.left = accessRegionRect.left;
         accessRegion.top = accessRegionRect.top;
@@ -371,7 +394,9 @@
 }
 
 int Gralloc::unlock(const native_handle_t* bufferHandle) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        return mGralloc4->unlock(bufferHandle);
+    } else if (mGralloc3) {
         return mGralloc3->unlock(bufferHandle);
     } else {
         return mGralloc2->unlock(bufferHandle);
@@ -379,7 +404,9 @@
 }
 
 void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        mGralloc4->freeBuffer(bufferHandle);
+    } else if (mGralloc3) {
         mGralloc3->freeBuffer(bufferHandle);
     } else {
         mGralloc2->freeBuffer(bufferHandle);
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 7811048..4294657 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
@@ -27,6 +27,7 @@
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <mapper-vts/2.0/MapperVts.h>
 #include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
 #include <utils/StrongPointer.h>
 
 #include "gtest/gtest.h"
@@ -44,8 +45,10 @@
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper;
 using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
 using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
 using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
 
 class ComposerClient;
 
@@ -153,6 +156,7 @@
   protected:
     std::shared_ptr<Gralloc2> mGralloc2 = nullptr;
     std::shared_ptr<Gralloc3> mGralloc3 = nullptr;
+    std::shared_ptr<Gralloc4> mGralloc4 = nullptr;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index d54da60..799ca91 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -27,12 +27,17 @@
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index fa5ace6..5d2f65d 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -22,6 +22,7 @@
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <mapper-vts/2.0/MapperVts.h>
 #include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
diff --git a/graphics/composer/2.2/default/Android.mk b/graphics/composer/2.2/default/Android.mk
index 7dedf61..cb551c6 100644
--- a/graphics/composer/2.2/default/Android.mk
+++ b/graphics/composer/2.2/default/Android.mk
@@ -11,8 +11,8 @@
 LOCAL_SHARED_LIBRARIES := \
         android.hardware.graphics.composer@2.1 \
         android.hardware.graphics.composer@2.2 \
-        android.hardware.graphics.mapper@2.0 \
-        android.hardware.graphics.mapper@3.0 \
+        android.hardware.graphics.composer@2.1-resources \
+        android.hardware.graphics.composer@2.2-resources \
         libbase \
         libbinder \
         libcutils \
diff --git a/graphics/composer/2.2/utils/hal/Android.bp b/graphics/composer/2.2/utils/hal/Android.bp
index 10dcae4..f334a11 100644
--- a/graphics/composer/2.2/utils/hal/Android.bp
+++ b/graphics/composer/2.2/utils/hal/Android.bp
@@ -19,9 +19,11 @@
     vendor_available: true,
     shared_libs: [
         "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-resources",
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-resources",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.2-command-buffer",
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
index c760d0a..512d39d 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -24,7 +24,7 @@
 #include <composer-hal/2.1/ComposerClient.h>
 #include <composer-hal/2.2/ComposerCommandEngine.h>
 #include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
@@ -89,7 +89,7 @@
 
         auto resources = static_cast<ComposerResources*>(mResources.get());
         const native_handle_t* readbackBuffer;
-        ComposerResources::ReplacedBufferHandle replacedReadbackBuffer;
+        ComposerResources::ReplacedHandle replacedReadbackBuffer(true);
         error = resources->getDisplayReadbackBuffer(display, buffer.getNativeHandle(),
                                                     &readbackBuffer, &replacedReadbackBuffer);
         if (error != Error::NONE) {
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
index 97e3a9e..d9f6226 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
@@ -23,7 +23,7 @@
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <composer-hal/2.1/ComposerCommandEngine.h>
 #include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
diff --git a/graphics/composer/2.2/utils/resources/Android.bp b/graphics/composer/2.2/utils/resources/Android.bp
new file mode 100644
index 0000000..752eb81
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "android.hardware.graphics.composer@2.2-resources",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/resources/ComposerResources.cpp b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..a0610a3
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ComposerResources 2.2"
+
+#include "composer-resources/2.2/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+Error ComposerDisplayResource::getReadbackBuffer(const native_handle_t* inHandle,
+                                                 const native_handle_t** outHandle,
+                                                 const native_handle** outReplacedHandle) {
+    const uint32_t slot = 0;
+    const bool fromCache = false;
+    return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+    auto resources = std::make_unique<ComposerResources>();
+    return resources->init() ? std::move(resources) : nullptr;
+}
+
+Error ComposerResources::getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+                                                  const native_handle_t** outHandle,
+                                                  ReplacedHandle* outReplacedHandle) {
+    // import buffer
+    const native_handle_t* importedHandle;
+    Error error = mImporter.importBuffer(rawHandle, &importedHandle);
+    if (error != Error::NONE) {
+        return error;
+    }
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+    auto iter = mDisplayResources.find(display);
+    if (iter == mDisplayResources.end()) {
+        mImporter.freeBuffer(importedHandle);
+        return Error::BAD_DISPLAY;
+    }
+    ComposerDisplayResource& displayResource =
+            *static_cast<ComposerDisplayResource*>(iter->second.get());
+
+    // update cache
+    const native_handle_t* replacedHandle;
+    error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
+    if (error != Error::NONE) {
+        mImporter.freeBuffer(importedHandle);
+        return error;
+    }
+
+    outReplacedHandle->reset(&mImporter, replacedHandle);
+    return Error::NONE;
+}
+
+}  // namespace hal
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
similarity index 90%
rename from graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
rename to graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
index 85b6651..33012e9 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
+++ b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
@@ -20,7 +20,7 @@
 #warning "ComposerResources.h included without LOG_TAG"
 #endif
 
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
 
 namespace android {
 namespace hardware {
@@ -33,7 +33,7 @@
 using V2_1::hal::ComposerHandleImporter;
 
 class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
-   public:
+  public:
     ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
                             uint32_t outputBufferCacheSize)
         : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
@@ -47,12 +47,12 @@
                                               outReplacedHandle);
     }
 
-   protected:
+  protected:
     ComposerHandleCache mReadbackBufferCache;
 };
 
 class ComposerResources : public V2_1::hal::ComposerResources {
-   public:
+  public:
     static std::unique_ptr<ComposerResources> create() {
         auto resources = std::make_unique<ComposerResources>();
         return resources->init() ? std::move(resources) : nullptr;
@@ -60,7 +60,7 @@
 
     Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
                                    const native_handle_t** outHandle,
-                                   ReplacedBufferHandle* outReplacedHandle) {
+                                   ReplacedHandle* outReplacedHandle) {
         // import buffer
         const native_handle_t* importedHandle;
         Error error = mImporter.importBuffer(rawHandle, &importedHandle);
@@ -76,7 +76,7 @@
             return Error::BAD_DISPLAY;
         }
         ComposerDisplayResource& displayResource =
-            *static_cast<ComposerDisplayResource*>(iter->second.get());
+                *static_cast<ComposerDisplayResource*>(iter->second.get());
 
         // update cache
         const native_handle_t* replacedHandle;
@@ -90,9 +90,9 @@
         return Error::NONE;
     }
 
-   protected:
+  protected:
     std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
-        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
+            ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
         return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
     }
 };
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 1754a43..5432882 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -34,6 +34,10 @@
         "libmath",
         "libnativewindow",
         "librenderengine",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     export_static_lib_headers: [
         "VtsHalHidlTargetTestBase",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index a380fc0..93b67f0 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -182,17 +182,23 @@
 
 Gralloc::Gralloc() {
     [this] {
-        ALOGD("Attempting to initialize gralloc3");
-        ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+        ALOGD("Attempting to initialize gralloc4");
+        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
                                                                        /*errOnFailure=*/false));
-        if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
-            mGralloc3 = nullptr;
-            ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
-            mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
-            if (!mGralloc2_1->getMapper()) {
-                mGralloc2_1 = nullptr;
-                ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
-                ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+        if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) {
+            mGralloc4 = nullptr;
+            ALOGD("Failed to initialize gralloc4, initializing gralloc3");
+            ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+                                                                           /*errOnFailure=*/false));
+            if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
+                mGralloc3 = nullptr;
+                ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
+                mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
+                if (!mGralloc2_1->getMapper()) {
+                    mGralloc2_1 = nullptr;
+                    ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
+                    ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+                }
             }
         }
     }();
@@ -201,7 +207,15 @@
 bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width,
                                  uint32_t height, uint32_t layerCount, PixelFormat format,
                                  uint64_t usage, uint32_t stride) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        IMapper4::BufferDescriptorInfo info{};
+        info.width = width;
+        info.height = height;
+        info.layerCount = layerCount;
+        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+        info.usage = usage;
+        return mGralloc4->validateBufferSize(bufferHandle, info, stride);
+    } else if (mGralloc3) {
         IMapper3::BufferDescriptorInfo info{};
         info.width = width;
         info.height = height;
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index d479aa7..7bb9121 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -81,14 +81,14 @@
             static_cast<float>(mDisplayFrame.left), static_cast<float>(mDisplayFrame.top),
             static_cast<float>(mDisplayFrame.right), static_cast<float>(mDisplayFrame.bottom));
 
-    const mat4 translation = mat4::translate(vec4(
-            (mTransform & Transform::FLIP_H ? -1.0f : 0.0f) * mDisplayFrame.right,
-            (mTransform & Transform::FLIP_V ? -1.0f : 0.0f) * mDisplayFrame.bottom, 0.0f, 1.0f));
+    const mat4 translation = mat4::translate(
+            vec4((mTransform & Transform::FLIP_H ? -mDisplayFrame.right : 0.0f),
+                 (mTransform & Transform::FLIP_V ? -mDisplayFrame.bottom : 0.0f), 0.0f, 1.0f));
 
     const mat4 scale = mat4::scale(vec4(mTransform & Transform::FLIP_H ? -1.0f : 1.0f,
                                         mTransform & Transform::FLIP_V ? -1.0f : 1.0f, 1.0f, 1.0f));
 
-    layerSettings.geometry.positionTransform = translation * scale;
+    layerSettings.geometry.positionTransform = scale * translation;
 
     return layerSettings;
 }
@@ -296,9 +296,9 @@
     layerSettings.source.buffer.buffer =
             new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
                               static_cast<int32_t>(mFormat), 1, mUsage, mStride);
-    // TODO(b/136483187): Why does this break the premultiply test
-    // layerSettings.source.buffer.usePremultipliedAlpha =
-    //      mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
+
+    layerSettings.source.buffer.usePremultipliedAlpha =
+            mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
 
     const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (mWidth);
     const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (mHeight);
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 8fa9b7b..5d22305 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
@@ -44,9 +44,11 @@
 using common::V1_1::RenderIntent;
 using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper;
 using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
 using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
 using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc;
 using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
 
 class ComposerClient;
 
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 1319035..2872880 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -19,31 +19,27 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
-        "VtsHalGraphicsComposerV2_2TargetTest.cpp",
-        "VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp",
+        "VtsHalGraphicsComposerV2_2TargetTest.cpp"
     ],
 
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
         "libfmq",
+        "libgui",
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
         "libprocessgroup",
         "libsync",
         "libui",
-        "libgui",
-        "libEGL",
-        "libGLESv1_CM",
-        "libGLESv2",
     ],
     static_libs: [
-        "librenderengine",
-        "libmath",
-        "libarect",
-        "libnativewindow",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
@@ -55,6 +51,9 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hardware.graphics.mapper@4.0-vts",
+        "librenderengine"
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp
deleted file mode 100644
index d694a5b..0000000
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2"
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
-#include <composer-vts/2.1/GraphicsComposerCallback.h>
-#include <composer-vts/2.1/TestCommandReader.h>
-#include <composer-vts/2.2/ComposerVts.h>
-#include <composer-vts/2.2/ReadbackVts.h>
-#include <composer-vts/2.2/RenderEngineVts.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferAllocator.h>
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_2 {
-namespace vts {
-namespace {
-
-using android::GraphicBuffer;
-using android::Rect;
-using android::hardware::hidl_handle;
-using common::V1_1::BufferUsage;
-using common::V1_1::Dataspace;
-using common::V1_1::PixelFormat;
-using mapper::V2_1::IMapper;
-using V2_1::Config;
-using V2_1::Display;
-using V2_1::vts::TestCommandReader;
-using vts::Gralloc;
-
-// 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 GraphicsCompositionComparisonTest : public ::testing::VtsHalHidlTargetTestBase {
-  protected:
-    using PowerMode = V2_1::IComposerClient::PowerMode;
-    void SetUp() override {
-        VtsHalHidlTargetTestBase::SetUp();
-        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();
-        Config activeConfig;
-        ASSERT_NO_FATAL_FAILURE(activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay));
-        ASSERT_NO_FATAL_FAILURE(
-                mDisplayWidth = mComposerClient->getDisplayAttribute(
-                        mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH));
-        ASSERT_NO_FATAL_FAILURE(
-                mDisplayHeight = mComposerClient->getDisplayAttribute(
-                        mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT));
-
-        setTestColorModes();
-
-        // explicitly disable vsync
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false));
-        mComposerCallback->setVsyncAllowed(false);
-
-        // set up command writer/reader and gralloc
-        mWriter = std::make_shared<CommandWriterBase>(1024);
-        mReader = std::make_unique<TestCommandReader>();
-        mGralloc = std::make_shared<Gralloc>();
-
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
-
-        ASSERT_NO_FATAL_FAILURE(
-                mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
-                        PixelFormat::RGBA_8888,
-                        renderengine::RenderEngine::USE_COLOR_MANAGEMENT |
-                                renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT)));
-
-        renderengine::DisplaySettings clientCompositionDisplay;
-        clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
-        clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
-        clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay);
-
-        mTestRenderEngine->initGraphicBuffer(
-                static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
-                static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN));
-        mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
-    }
-
-    void TearDown() override {
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF));
-        EXPECT_EQ(0, mReader->mErrors.size());
-        EXPECT_EQ(0, mReader->mCompositionChanges.size());
-        if (mComposerCallback != nullptr) {
-            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
-            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
-            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
-        }
-        VtsHalHidlTargetTestBase::TearDown();
-    }
-
-    void clearCommandReaderState() {
-        mReader->mCompositionChanges.clear();
-        mReader->mErrors.clear();
-    }
-
-    void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
-        for (auto layer : layers) {
-            layer->write(mWriter);
-        }
-        execute();
-    }
-
-    void execute() {
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
-    }
-
-    std::unique_ptr<Composer> mComposer;
-    std::shared_ptr<ComposerClient> mComposerClient;
-
-    sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
-    // the first display and is assumed never to be removed
-    Display mPrimaryDisplay;
-    int32_t mDisplayWidth;
-    int32_t mDisplayHeight;
-    std::vector<ColorMode> mTestColorModes;
-    std::shared_ptr<CommandWriterBase> mWriter;
-    std::unique_ptr<TestCommandReader> mReader;
-    std::shared_ptr<Gralloc> mGralloc;
-    std::unique_ptr<TestRenderEngine> mTestRenderEngine;
-
-    bool mHasReadbackBuffer;
-    PixelFormat mPixelFormat;
-    Dataspace mDataspace;
-
-  private:
-    Display waitForFirstDisplay() {
-        while (true) {
-            std::vector<Display> displays = mComposerCallback->getDisplays();
-            if (displays.empty()) {
-                usleep(5 * 1000);
-                continue;
-            }
-            return displays[0];
-        }
-    }
-
-    void setTestColorModes() {
-        mTestColorModes.clear();
-        mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError,
-                                                                          const auto& tmpModes) {
-            ASSERT_EQ(Error::NONE, tmpError);
-            for (ColorMode mode : tmpModes) {
-                if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(),
-                              mode) != ReadbackHelper::colorModes.end()) {
-                    mTestColorModes.push_back(mode);
-                }
-            }
-        });
-    }
-};
-
-TEST_F(GraphicsCompositionComparisonTest, SingleSolidColorLayer) {
-    for (ColorMode mode : mTestColorModes) {
-        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
-                  << std::endl;
-        mWriter->selectDisplay(mPrimaryDisplay);
-        ASSERT_NO_FATAL_FAILURE(
-                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
-
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
-        if (!mHasReadbackBuffer) {
-            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
-            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-            return;
-        }
-
-        auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
-        IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
-        layer->setColor(BLUE);
-        layer->setDisplayFrame(coloredSquare);
-        layer->setZOrder(10);
-
-        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
-        // expected color for each pixel
-        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
-
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
-        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-        writeLayers(layers);
-        ASSERT_EQ(0, mReader->mErrors.size());
-        mWriter->validateDisplay();
-        execute();
-        // if hwc cannot handle and asks for composition change,
-        // just succeed the test
-        if (mReader->mCompositionChanges.size() != 0) {
-            clearCommandReaderState();
-            GTEST_SUCCEED();
-            return;
-        }
-        ASSERT_EQ(0, mReader->mErrors.size());
-        mWriter->presentDisplay();
-        execute();
-        ASSERT_EQ(0, mReader->mErrors.size());
-
-        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-        mTestRenderEngine->setRenderLayers(layers);
-        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
-        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
-    }
-}
-
-}  // namespace
-}  // namespace vts
-}  // namespace V2_2
-}  // namespace composer
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 92c03f0..ade7a38 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -21,7 +21,14 @@
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
 #include <composer-vts/2.2/ReadbackVts.h>
+#include <composer-vts/2.2/RenderEngineVts.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
 
 namespace android {
 namespace hardware {
@@ -31,14 +38,17 @@
 namespace vts {
 namespace {
 
+using android::GraphicBuffer;
+using android::Rect;
 using android::hardware::hidl_handle;
 using common::V1_1::BufferUsage;
 using common::V1_1::Dataspace;
 using common::V1_1::PixelFormat;
 using mapper::V2_1::IMapper;
+using V2_1::Config;
 using V2_1::Display;
-using V2_1::Layer;
 using V2_1::vts::TestCommandReader;
+using vts::Gralloc;
 
 // Test environment for graphics.composer
 class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -55,8 +65,8 @@
     GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
 };
 
-class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class GraphicsCompositionTest : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
     using PowerMode = V2_1::IComposerClient::PowerMode;
     void SetUp() override {
         VtsHalHidlTargetTestBase::SetUp();
@@ -90,6 +100,22 @@
         mGralloc = std::make_shared<Gralloc>();
 
         ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
+
+        ASSERT_NO_FATAL_FAILURE(
+                mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
+                        PixelFormat::RGBA_8888,
+                        renderengine::RenderEngine::USE_COLOR_MANAGEMENT |
+                                renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT)));
+
+        renderengine::DisplaySettings clientCompositionDisplay;
+        clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
+        clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
+        clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay);
+
+        mTestRenderEngine->initGraphicBuffer(
+                static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
+                static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN));
+        mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
     }
 
     void TearDown() override {
@@ -132,6 +158,7 @@
     std::shared_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<TestCommandReader> mReader;
     std::shared_ptr<Gralloc> mGralloc;
+    std::unique_ptr<TestRenderEngine> mTestRenderEngine;
 
     bool mHasReadbackBuffer;
     PixelFormat mPixelFormat;
@@ -166,7 +193,7 @@
     }
 };
 
-TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) {
+TEST_F(GraphicsCompositionTest, SingleSolidColorLayer) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -222,10 +249,13 @@
         ASSERT_EQ(0, mReader->mErrors.size());
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) {
+TEST_F(GraphicsCompositionTest, SetLayerBuffer) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -291,10 +321,13 @@
         ASSERT_EQ(0, mReader->mErrors.size());
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) {
+TEST_F(GraphicsCompositionTest, SetLayerBufferNoEffect) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -356,7 +389,7 @@
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, ClientComposition) {
+TEST_F(GraphicsCompositionTest, ClientComposition) {
     ASSERT_NO_FATAL_FAILURE(
             mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
 
@@ -473,7 +506,7 @@
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) {
+TEST_F(GraphicsCompositionTest, DeviceAndClientComposition) {
     ASSERT_NO_FATAL_FAILURE(
             mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
 
@@ -599,7 +632,7 @@
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) {
+TEST_F(GraphicsCompositionTest, SetLayerDamage) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -684,7 +717,7 @@
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) {
+TEST_F(GraphicsCompositionTest, SetLayerPlaneAlpha) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -739,10 +772,13 @@
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) {
+TEST_F(GraphicsCompositionTest, SetLayerSourceCrop) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -807,10 +843,13 @@
         execute();
         ASSERT_EQ(0, mReader->mErrors.size());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) {
+TEST_F(GraphicsCompositionTest, SetLayerZOrder) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -891,20 +930,23 @@
         ASSERT_EQ(0, mReader->mErrors.size());
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest,
-                                              public ::testing::WithParamInterface<float> {
-   public:
+class GraphicsBlendModeCompositionTest : public GraphicsCompositionTest,
+                                         public ::testing::WithParamInterface<float> {
+  public:
     void SetUp() override {
-        GraphicsComposerReadbackTest::SetUp();
+        GraphicsCompositionTest::SetUp();
         mTestColorModes = {ColorMode::SRGB};  // TODO: add more color mode support
         mBackgroundColor = BLACK;
         mTopLayerColor = RED;
     }
 
-    void TearDown() override { GraphicsComposerReadbackTest::TearDown(); }
+    void TearDown() override { GraphicsCompositionTest::TearDown(); }
 
     void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; }
 
@@ -976,7 +1018,7 @@
     IComposerClient::Color mTopLayerColor;
 };
 
-TEST_P(GraphicsComposerBlendModeReadbackTest, None) {
+TEST_P(GraphicsBlendModeCompositionTest, None) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -1026,12 +1068,15 @@
         ASSERT_EQ(0, mReader->mErrors.size());
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
 // TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane
 // alpha of .2, expected 10.2
-TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) {
+TEST_P(GraphicsBlendModeCompositionTest, DISABLED_Coverage) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -1084,7 +1129,7 @@
     }
 }
 
-TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) {
+TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -1132,16 +1177,19 @@
         execute();
         ASSERT_EQ(0, mReader->mErrors.size());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest,
+INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsBlendModeCompositionTest,
                         ::testing::Values(.2, 1.0));
 
-class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTest {
-   protected:
+class GraphicsTransformCompositionTest : public GraphicsCompositionTest {
+  protected:
     void SetUp() override {
-        GraphicsComposerReadbackTest::SetUp();
+        GraphicsCompositionTest::SetUp();
 
         mWriter->selectDisplay(mPrimaryDisplay);
 
@@ -1176,7 +1224,7 @@
     int mSideLength;
 };
 
-TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) {
+TEST_F(GraphicsTransformCompositionTest, FLIP_H) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -1225,10 +1273,13 @@
         ASSERT_EQ(0, mReader->mErrors.size());
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) {
+TEST_F(GraphicsTransformCompositionTest, FLIP_V) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -1277,10 +1328,13 @@
         execute();
         ASSERT_EQ(0, mReader->mErrors.size());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
-TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) {
+TEST_F(GraphicsTransformCompositionTest, ROT_180) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
@@ -1330,6 +1384,9 @@
         execute();
         ASSERT_EQ(0, mReader->mErrors.size());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
 }
 
diff --git a/graphics/composer/2.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp
index 07afd6c..8103b89 100644
--- a/graphics/composer/2.3/default/Android.bp
+++ b/graphics/composer/2.3/default/Android.bp
@@ -28,8 +28,8 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2-resources",
         "libbase",
         "libbinder",
         "libcutils",
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
index b289b6a..04530d3 100644
--- 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
@@ -21,9 +21,9 @@
 #endif
 
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
-#include <composer-hal/2.2/ComposerResources.h>
 #include <composer-hal/2.3/ComposerCommandEngine.h>
 #include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
index 1a40d96..329dbed 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -23,8 +23,8 @@
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <composer-hal/2.1/ComposerCommandEngine.h>
 #include <composer-hal/2.2/ComposerCommandEngine.h>
-#include <composer-hal/2.2/ComposerResources.h>
 #include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 2766638..965c8fe 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -29,6 +29,7 @@
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
@@ -41,6 +42,8 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp
index 1bf51e0..a44e687 100644
--- a/graphics/composer/2.4/default/Android.bp
+++ b/graphics/composer/2.4/default/Android.bp
@@ -29,8 +29,8 @@
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
         "android.hardware.graphics.composer@2.4",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2-resources",
         "libbase",
         "libbinder",
         "libcutils",
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index d437f24..6ee7873 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -27,6 +27,8 @@
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
@@ -38,6 +40,11 @@
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@2.1-vts",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/health/storage/1.0/default/service.cpp b/health/storage/1.0/default/service.cpp
index f4296f1..6f6ebc8 100644
--- a/health/storage/1.0/default/service.cpp
+++ b/health/storage/1.0/default/service.cpp
@@ -32,7 +32,7 @@
     configureRpcThreadpool(1, true);
 
     sp<IStorage> service = new Storage();
-    LazyServiceRegistrar registrar;
+    auto registrar = LazyServiceRegistrar::getInstance();
     status_t result = registrar.registerService(service);
 
     if (result != OK) {
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.h b/neuralnetworks/1.0/vts/functional/GeneratedTests.h
index 11ee5e8..5cabf68 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTests.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.h
@@ -32,7 +32,4 @@
 
 using namespace android::hardware::neuralnetworks::V1_0::vts::functional;
 
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-
 }  // namespace android::hardware::neuralnetworks::V1_0::generated_tests
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.h b/neuralnetworks/1.1/vts/functional/GeneratedTests.h
index 2343a4f..80442bf 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTests.h
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.h
@@ -34,6 +34,5 @@
 
 using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
 using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_1::Model;
 
 }  // namespace android::hardware::neuralnetworks::V1_1::generated_tests
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 082d758..5907646 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -35,10 +35,11 @@
 #include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
-namespace android::hardware::neuralnetworks::V1_2::generated_tests::
-        mobilenet_224_gender_basic_fixed {
+namespace android::hardware::neuralnetworks::V1_2 {
+namespace generated_tests::mobilenet_224_gender_basic_fixed {
 Model createTestModel();
-}  // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_224_gender_basic_fixed
+}  // namespace generated_tests::mobilenet_224_gender_basic_fixed
+}  // namespace android::hardware::neuralnetworks::V1_2
 
 namespace generated_tests::mobilenet_224_gender_basic_fixed {
 std::vector<test_helper::MixedTypedExample>& get_examples();
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.h b/neuralnetworks/1.2/vts/functional/GeneratedTests.h
index f393eb2..9842036 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTests.h
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.h
@@ -35,6 +35,5 @@
 
 using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
 using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_2::Model;
 
 }  // namespace android::hardware::neuralnetworks::V1_2::generated_tests
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
new file mode 100644
index 0000000..b54413d
--- /dev/null
+++ b/tv/tuner/1.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.tv.tuner@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IFrontend.hal",
+        "IFrontendCallback.hal",
+        "ITuner.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
new file mode 100644
index 0000000..05cee91
--- /dev/null
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.tv.tuner@1.0;
+
+import IFrontendCallback;
+
+/**
+ * A Tuner Frontend is used to tune to a frequency and lock signal. It provide
+ * live data feed to Tuner Demux interface.
+ */
+interface IFrontend {
+    /**
+     * Set the callback
+     *
+     * It is used by the client to receive events from the Frontend.
+     * Only one callback for one Frontend instance is supported. The callback
+     * will be replaced if it's set again.
+     *
+     * @param callback Callback object to pass Frontend events to the system.
+     *        The previously registered callback must be replaced with this one.
+     *        It can be null.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if callback can't be set at current stage,
+     *         UNKNOWN_ERROR if callback setting failed for other reasons.
+     */
+    setCallback(IFrontendCallback callback) generates (Result result);
+
+    /**
+     * Tuning Frontend
+     *
+     * It is used by the client to lock a frequency by providing signal
+     * delivery information. If previous tuning isn't completed, this call must
+     * stop previous tuning, and start a new tuning. Tune is a async call.
+     * LOCKED or NO_SIGNAL eventi is sent back to caller through callback.
+     *
+     * @param settings Signal delivery information which frontend can use to
+     * search and lock the signal.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     */
+    tune(FrontendSettings settings) generates (Result result);
+
+    /**
+     * Stop the tuning
+     *
+     * It is used by the client to stop a previous tuning.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successfully stop tuning.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stopTune() generates (Result result);
+
+    /**
+     * Release the Frontend instance
+     *
+     * It is used by the client to release the frontend instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal
new file mode 100644
index 0000000..e907049
--- /dev/null
+++ b/tv/tuner/1.0/IFrontendCallback.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+interface IFrontendCallback {
+    /**
+     * Notify the client that a new event happened on the frontend.
+     *
+     * @param frontendEventType the event type.
+     */
+    oneway onEvent(FrontendEventType frontendEventType);
+
+    /**
+     * The callback function that must be called by HAL implementation to notify
+     * the client of new DiSEqC message.
+     *
+     * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite
+     * Equipment Control) message which is specified by EUTELSAT Bus Functional
+     * Specification Version 4.2.
+     */
+    oneway onDiseqcMessage(vec<uint8_t> diseqcMessage);
+};
+
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
new file mode 100644
index 0000000..5a5f547
--- /dev/null
+++ b/tv/tuner/1.0/ITuner.hal
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+import IFrontend;
+
+/**
+ * Top level interface to manage Frontend, Demux and Decrambler hardware
+ * resouces which are needed for Android TV.
+ */
+interface ITuner {
+    /**
+     * Get Frontend IDs
+     *
+     * It is used by the client to get all available frontends' IDs.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     * @return frontendIds an array of FrontendId for the available frontends.
+     */
+    getFrontendIds() generates (Result result, vec<FrontendId> frontendIds);
+
+    /**
+     * Create a new instance of Frontend given a frontendId.
+     *
+     * It is used by the client to create a frontend instance.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return frontend the newly created frontend interface.
+     */
+    openFrontendById(FrontendId frontendId)
+        generates (Result result, IFrontend frontend);
+
+};
+
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
new file mode 100644
index 0000000..cc8d1f5
--- /dev/null
+++ b/tv/tuner/1.0/default/Android.bp
@@ -0,0 +1,43 @@
+cc_defaults {
+    name: "tuner_service_defaults",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "Frontend.cpp",
+        "Tuner.cpp",
+        "service.cpp",
+    ],
+
+    compile_multilib: "first",
+
+    shared_libs: [
+        "android.hardware.tv.tuner@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+    header_libs: [
+        "media_plugin_headers",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.tv.tuner@1.0-service",
+    vintf_fragments: ["android.hardware.tv.tuner@1.0-service.xml"],
+    defaults: ["tuner_service_defaults"],
+    init_rc: ["android.hardware.tv.tuner@1.0-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.tv.tuner@1.0-service-lazy",
+    vintf_fragments: ["android.hardware.tv.tuner@1.0-service-lazy.xml"],
+    overrides: ["android.hardware.tv.tuner@1.0-service"],
+    defaults: ["tuner_service_defaults"],
+    init_rc: ["android.hardware.tv.tuner@1.0-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
new file mode 100644
index 0000000..3dcc2b1
--- /dev/null
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.0-Frontend"
+
+#include "Frontend.h"
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Frontend::Frontend() {
+    // Init callback to nullptr
+    mCallback = nullptr;
+}
+
+Frontend::Frontend(FrontendType type, FrontendId id) {
+    mType = type;
+    mId = id;
+    // Init callback to nullptr
+    mCallback = nullptr;
+}
+
+Frontend::~Frontend() {}
+
+Return<Result> Frontend::close() {
+    ALOGV("%s", __FUNCTION__);
+    // Reset callback
+    mCallback = nullptr;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setCallback(const sp<IFrontendCallback>& callback) {
+    ALOGV("%s", __FUNCTION__);
+    if (callback == nullptr) {
+        ALOGW("[   WARN   ] Set Frontend callback with nullptr");
+        return Result::INVALID_ARGUMENT;
+    }
+
+    mCallback = callback;
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::tune(const FrontendSettings& /* settings */) {
+    ALOGV("%s", __FUNCTION__);
+    if (mCallback == nullptr) {
+        ALOGW("[   WARN   ] Frontend callback is not set when tune");
+        return Result::INVALID_STATE;
+    }
+
+    mCallback->onEvent(FrontendEventType::NO_SIGNAL);
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::stopTune() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+FrontendType Frontend::getFrontendType() {
+    return mType;
+}
+
+FrontendId Frontend::getFrontendId() {
+    return mId;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
new file mode 100644
index 0000000..f77a0d8
--- /dev/null
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
+
+#include <android/hardware/tv/tuner/1.0/IFrontend.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::FrontendType;
+using ::android::hardware::tv::tuner::V1_0::IFrontend;
+using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+class Frontend : public IFrontend {
+  public:
+    Frontend();
+    Frontend(FrontendType type, FrontendId id);
+
+    virtual Return<Result> close() override;
+
+    virtual Return<Result> setCallback(const sp<IFrontendCallback>& callback) override;
+
+    virtual Return<Result> tune(const FrontendSettings& settings) override;
+
+    virtual Return<Result> stopTune() override;
+
+    FrontendType getFrontendType();
+
+    FrontendId getFrontendId();
+
+  private:
+    virtual ~Frontend();
+    sp<IFrontendCallback> mCallback;
+    FrontendType mType = FrontendType::UNDEFINED;
+    FrontendId mId = 0;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
diff --git a/tv/tuner/1.0/default/OWNERS b/tv/tuner/1.0/default/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/default/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
new file mode 100644
index 0000000..67ec754
--- /dev/null
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.0-Tuner"
+
+#include "Tuner.h"
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+#include "Frontend.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Tuner::Tuner() {
+    // Static Frontends array to maintain local frontends information
+    // Array index matches their FrontendId in the default impl
+    mFrontendSize = 8;
+    mFrontends.resize(mFrontendSize);
+    mFrontends[0] = new Frontend();
+    mFrontends[1] = new Frontend(FrontendType::ATSC, 1);
+    mFrontends[2] = new Frontend(FrontendType::DVBC, 2);
+    mFrontends[3] = new Frontend(FrontendType::DVBS, 3);
+    mFrontends[4] = new Frontend(FrontendType::DVBT, 4);
+    mFrontends[5] = new Frontend(FrontendType::ISDBT, 5);
+    mFrontends[6] = new Frontend(FrontendType::ANALOG, 6);
+    mFrontends[7] = new Frontend(FrontendType::ATSC, 7);
+}
+
+Tuner::~Tuner() {}
+
+Return<void> Tuner::getFrontendIds(getFrontendIds_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<FrontendId> frontendIds;
+    frontendIds.resize(mFrontendSize);
+    for (int i = 0; i < mFrontendSize; i++) {
+        frontendIds[i] = mFrontends[i]->getFrontendId();
+    }
+
+    _hidl_cb(Result::SUCCESS, frontendIds);
+    return Void();
+}
+
+Return<void> Tuner::openFrontendById(uint32_t frontendId, openFrontendById_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (frontendId >= mFrontendSize || frontendId < 0) {
+        ALOGW("[   WARN   ] Frontend with id %d isn't available", frontendId);
+        _hidl_cb(Result::UNAVAILABLE, nullptr);
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, mFrontends[frontendId]);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
new file mode 100644
index 0000000..2152c89
--- /dev/null
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include "Frontend.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Tuner : public ITuner {
+  public:
+    Tuner();
+    virtual Return<void> getFrontendIds(getFrontendIds_cb _hidl_cb) override;
+
+    virtual Return<void> openFrontendById(uint32_t frontendId,
+                                          openFrontendById_cb _hidl_cb) override;
+
+  private:
+    virtual ~Tuner();
+    // Static mFrontends array to maintain local frontends information
+    vector<sp<Frontend>> mFrontends;
+    // To maintain how many Frontends we have
+    int mFrontendSize;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc
new file mode 100644
index 0000000..ad72fae
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.tuner-hal-1-0 /vendor/bin/hw/android.hardware.tv.tuner@1.0-service-lazy
+    interface android.hardware.tv.tuner@1.0::ITuner default
+    oneshot
+    disabled
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml
new file mode 100644
index 0000000..4bcfe10
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.tv.tuner</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc
new file mode 100644
index 0000000..6d59ed7
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc
@@ -0,0 +1,6 @@
+service vendor.tuner-hal-1-0 /vendor/bin/hw/android.hardware.tv.tuner@1.0-service
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml
new file mode 100644
index 0000000..4bcfe10
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.tv.tuner</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp
new file mode 100644
index 0000000..581d269
--- /dev/null
+++ b/tv/tuner/1.0/default/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.tv.tuner@1.0-service-lazy"
+#else
+#define LOG_TAG "android.hardware.tv.tuner@1.0-service"
+#endif
+
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "Tuner.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::implementation::Tuner;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<ITuner> service = new Tuner();
+    android::status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
+        status = serviceRegistrar->registerService(service);
+    } else {
+        status = service->registerAsService();
+    }
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering tuner service: %d", status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
new file mode 100644
index 0000000..1ca7fda
--- /dev/null
+++ b/tv/tuner/1.0/types.hal
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+import android.hidl.safe_union@1.0;
+
+@export
+enum Result : int32_t {
+    SUCCESS,
+    UNAVAILABLE,
+    NOT_INITIALIZED,
+    INVALID_STATE,
+    INVALID_ARGUMENT,
+    OUT_OF_MEMORY,
+    UNKNOWN_ERROR,
+};
+
+/**
+ * Frontend ID.
+ */
+typedef uint32_t FrontendId;
+
+/**
+ *  Frontend Types.
+ */
+@export
+enum FrontendType : uint32_t {
+    UNDEFINED = 0,
+    ANALOG,
+    ATSC,
+    DVBC,
+    DVBS,
+    DVBT,
+    ISDBT,
+};
+
+/**
+ *  Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
+ *  It's a 4-bit field specifying the inner FEC scheme used according to the
+ *  table 35 in the spec.
+ */
+@export
+enum FrontendInnerFec : uint32_t {
+    /* Not defined */
+    FEC_UNDEFINED = 0,
+    /* 1/2 conv. code rate */
+    FEC_1_2 = 1 << 0,
+    /* 2/3 conv. code rate */
+    FEC_2_3 = 1 << 1,
+    /* 3/4 conv. code rate */
+    FEC_3_4 = 1 << 2,
+    /* 5/6 conv. code rate */
+    FEC_5_6 = 1 << 3,
+    /* 7/8 conv. code rate */
+    FEC_7_8 = 1 << 4,
+    /* 8/9 conv. code rate */
+    FEC_8_9 = 1 << 5,
+    /* 3/5 conv. code rate */
+    FEC_3_5 = 1 << 6,
+    /* 4/5 conv. code rate */
+    FEC_4_5 = 1 << 7,
+    /* 9/10 conv. code rate */
+    FEC_9_10 = 1 << 8,
+    /* hardware is able to detect and set FEC automatically */
+    FEC_AUTO = 1 << 9,
+};
+
+/**
+ *  Modulation Type for ATSC.
+ */
+@export
+enum FrontendAtscModulation : uint32_t {
+    UNDEFINED = 0,
+    MOD_8VSB = 1 << 0,
+    MOD_16VSB = 1 << 1,
+};
+
+/**
+ *  Signal Setting for ATSC Frontend.
+ */
+struct FrontendAtscSettings {
+    /** Signal frequencey in Herhz */
+    uint32_t frequency;
+    FrontendAtscModulation modulation;
+};
+
+/**
+ *  Signal Setting for DVBT Frontend.
+ */
+struct FrontendDvbtSettings {
+    /** Signal frequencey in Herhz */
+    uint32_t frequency;
+    FrontendAtscModulation modulation;
+    FrontendInnerFec fec;
+};
+
+/**
+ *  Modulation Type for ATSC.
+ */
+safe_union FrontendSettings {
+    FrontendAtscSettings atsc;
+    FrontendDvbtSettings dvbt;
+};
+
+/**
+ * Frontend Event Type.
+ */
+@export
+enum FrontendEventType : uint32_t {
+    /**
+     * If frontend locked the signal which is specified by tune method, HAL sent
+     * Locked event.
+     */
+    LOCKED,
+    /**
+     * If frontend can't locked the signal which is specified by tune method,
+     * HAL sent NO_SIGNAL event.
+     */
+    NO_SIGNAL,
+    /**
+     * If frontend detect that the locked signal get lost, HAL sent LOST_LOCK
+     * event.
+     */
+    LOST_LOCK,
+};
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..faf566c
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalTvTunerV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalTvTunerV1_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.tuner@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlallocatorutils",
+        "libhidlmemory",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
new file mode 100644
index 0000000..4840a02
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Tuner_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IFrontend.h>
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define WAIT_TIMEOUT 3000000000
+
+using android::Condition;
+using android::IMemory;
+using android::IMemoryHeap;
+using android::MemoryDealer;
+using android::Mutex;
+using android::sp;
+using android::hardware::fromHeap;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::HidlMemory;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
+using android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using android::hardware::tv::tuner::V1_0::FrontendEventType;
+using android::hardware::tv::tuner::V1_0::FrontendId;
+using android::hardware::tv::tuner::V1_0::FrontendInnerFec;
+using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::IFrontend;
+using android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::Result;
+
+namespace {
+
+class FrontendCallback : public IFrontendCallback {
+  public:
+    virtual Return<void> onEvent(FrontendEventType frontendEventType) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mEventReceived = true;
+        mEventType = frontendEventType;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mDiseqcMessageReceived = true;
+        mEventMessage = diseqcMessage;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    void testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings);
+    void testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings);
+
+  private:
+    bool mEventReceived = false;
+    bool mDiseqcMessageReceived = false;
+    FrontendEventType mEventType;
+    hidl_vec<uint8_t> mEventMessage;
+    android::Mutex mMsgLock;
+    android::Condition mMsgCondition;
+};
+
+void FrontendCallback::testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings) {
+    Result result = frontend->tune(settings);
+
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+}
+
+void FrontendCallback::testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings) {
+    Result result = frontend->tune(settings);
+
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mDiseqcMessageReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "diseqc message not received within timeout";
+            return;
+        }
+    }
+}
+
+// Test environment for Tuner HIDL HAL.
+class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static TunerHidlEnvironment* Instance() {
+        static TunerHidlEnvironment* instance = new TunerHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<ITuner>(); }
+};
+
+class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+  public:
+    virtual void SetUp() override {
+        mService = ::testing::VtsHalHidlTargetTestBase::getService<ITuner>(
+                TunerHidlEnvironment::Instance()->getServiceName<ITuner>());
+        ASSERT_NE(mService, nullptr);
+    }
+
+    sp<ITuner> mService;
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<IFrontend> mFrontend;
+    sp<FrontendCallback> mFrontendCallback;
+
+    ::testing::AssertionResult createFrontend(int32_t frontendId);
+    ::testing::AssertionResult tuneFrontend(int32_t frontendId);
+    ::testing::AssertionResult stopTuneFrontend(int32_t frontendId);
+    ::testing::AssertionResult closeFrontend(int32_t frontendId);
+};
+
+::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
+    Result status;
+
+    mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
+        mFrontend = frontend;
+        status = result;
+    });
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    mFrontendCallback = new FrontendCallback();
+    auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
+
+    return ::testing::AssertionResult(callbackStatus.isOk());
+}
+
+::testing::AssertionResult TunerHidlTest::tuneFrontend(int32_t frontendId) {
+    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Frontend Settings for testing
+    FrontendSettings frontendSettings;
+    FrontendAtscSettings frontendAtscSettings{
+            .frequency = 0,
+            .modulation = FrontendAtscModulation::UNDEFINED,
+    };
+    frontendSettings.atsc() = frontendAtscSettings;
+    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
+
+    FrontendDvbtSettings frontendDvbtSettings{
+            .frequency = 0,
+            .modulation = FrontendAtscModulation::UNDEFINED,
+            .fec = FrontendInnerFec::FEC_UNDEFINED,
+    };
+    frontendSettings.dvbt(frontendDvbtSettings);
+    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
+
+    return ::testing::AssertionResult(true);
+}
+
+::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) {
+    Result status;
+    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mFrontend->stopTune();
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) {
+    Result status;
+    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mFrontend->close();
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+TEST_F(TunerHidlTest, CreateFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("Create Frontends");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(createFrontend(feIds[i]));
+    }
+}
+
+TEST_F(TunerHidlTest, TuneFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("Tune Frontends and check callback onEvent");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(tuneFrontend(feIds[i]));
+    }
+}
+
+TEST_F(TunerHidlTest, StopTuneFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("stopTune Frontends");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(stopTuneFrontend(feIds[i]));
+    }
+}
+
+TEST_F(TunerHidlTest, CloseFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("Close Frontends");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(closeFrontend(feIds[i]));
+    }
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(TunerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    TunerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/1.3/default/service.cpp b/wifi/1.3/default/service.cpp
index fcbc37c..0b41d28 100644
--- a/wifi/1.3/default/service.cpp
+++ b/wifi/1.3/default/service.cpp
@@ -58,7 +58,7 @@
             std::make_shared<WifiIfaceUtil>(iface_tool),
             std::make_shared<WifiFeatureFlags>());
     if (kLazyService) {
-        LazyServiceRegistrar registrar;
+        auto registrar = LazyServiceRegistrar::getInstance();
         CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
             << "Failed to register wifi HAL";
     } else {