graphics: add composer 2.2 default impl

This adds

  android.hardware.graphics.composer@2.2-hal
  android.hardware.graphics.composer@2.2-passthrough
  android.hardware.graphics.composer@2.2-service

The -hal module makes it easier to write composer 2.2 HAL and is
reusable by vendors.  The -passthrough module provides a HwcHal
class that implements ComposerHal 2.2 on top of hwcomposer2, and is
also resuable by vendors.  Finally, the -service module provides a
(stub) default implementation.

Test: boots and VTS
Change-Id: I4f940a9dea656abc7d9d485bf48d852c13d2ed56
diff --git a/graphics/composer/2.2/default/Android.bp b/graphics/composer/2.2/default/Android.bp
new file mode 100644
index 0000000..906479e
--- /dev/null
+++ b/graphics/composer/2.2/default/Android.bp
@@ -0,0 +1,31 @@
+cc_binary {
+    name: "android.hardware.graphics.composer@2.2-service",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: ["service.cpp"],
+    init_rc: ["android.hardware.graphics.composer@2.2-service.rc"],
+    header_libs: [
+        "android.hardware.graphics.composer@2.2-passthrough",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.mapper@2.0",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwc2on1adapter",
+        "libhwc2onfbadapter",
+        "liblog",
+        "libsync",
+        "libutils",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"ComposerHal\""
+    ],
+}
diff --git a/graphics/composer/2.2/default/OWNERS b/graphics/composer/2.2/default/OWNERS
new file mode 100644
index 0000000..4714be2
--- /dev/null
+++ b/graphics/composer/2.2/default/OWNERS
@@ -0,0 +1,5 @@
+# Graphics team
+courtneygo@google.com
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
new file mode 100644
index 0000000..a41d902
--- /dev/null
+++ b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
@@ -0,0 +1,6 @@
+service vendor.hwcomposer-2-2 /vendor/bin/hw/android.hardware.graphics.composer@2.2-service
+    class hal animation
+    user system
+    group graphics drmrpc
+    capabilities SYS_NICE
+    onrestart restart surfaceflinger
diff --git a/graphics/composer/2.2/default/service.cpp b/graphics/composer/2.2/default/service.cpp
new file mode 100644
index 0000000..8c5ef18
--- /dev/null
+++ b/graphics/composer/2.2/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.2/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_2::IComposer;
+using android::hardware::graphics::composer::V2_2::passthrough::HwcLoader;
+
+int main() {
+    // the conventional HAL might start binder services
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+    android::ProcessState::self()->startThreadPool();
+
+    // same as SF main thread
+    struct sched_param param = {0};
+    param.sched_priority = 2;
+    if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+    }
+
+    android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+    android::sp<IComposer> composer = HwcLoader::load();
+    if (composer == nullptr) {
+        return 1;
+    }
+    if (composer->registerAsService() != android::NO_ERROR) {
+        ALOGE("failed to register service");
+        return 1;
+    }
+
+    android::hardware::joinRpcThreadpool();
+
+    ALOGE("service is terminating");
+    return 1;
+}
diff --git a/graphics/composer/2.2/utils/hal/Android.bp b/graphics/composer/2.2/utils/hal/Android.bp
new file mode 100644
index 0000000..10dcae4
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.2-hal",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.2",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.2",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.1-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.1-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/Composer.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/Composer.h
new file mode 100644
index 0000000..58bbaa5
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/Composer.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <composer-hal/2.1/Composer.h>
+#include <composer-hal/2.2/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_1::hal::detail::ComposerImpl<Interface, Hal> {
+   public:
+    static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+        return std::make_unique<ComposerImpl>(std::move(hal));
+    }
+
+    ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_1(std::move(hal)) {}
+
+   protected:
+    V2_1::IComposerClient* createClient() override {
+        auto client = ComposerClient::create(mHal.get());
+        if (!client) {
+            return nullptr;
+        }
+
+        auto clientDestroyed = [this]() { onClientDestroyed(); };
+        client->setOnClientDestroyed(clientDestroyed);
+
+        return client.release();
+    }
+
+   private:
+    using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+    using BaseType2_1::mHal;
+    using BaseType2_1::onClientDestroyed;
+};
+
+}  // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+}  // 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/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
new file mode 100644
index 0000000..d550f83
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#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>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_1::hal::detail::ComposerClientImpl<Interface, Hal> {
+   public:
+    static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+        auto client = std::make_unique<ComposerClientImpl>(hal);
+        return client->init() ? std::move(client) : nullptr;
+    }
+
+    ComposerClientImpl(Hal* hal) : BaseType2_1(hal) {}
+
+    // IComposerClient 2.2 interface
+
+    Return<void> getPerFrameMetadataKeys(
+        Display display, IComposerClient::getPerFrameMetadataKeys_cb hidl_cb) override {
+        std::vector<IComposerClient::PerFrameMetadataKey> keys;
+        Error error = mHal->getPerFrameMetadataKeys(display, &keys);
+        hidl_cb(error, keys);
+        return Void();
+    }
+
+    Return<void> getReadbackBufferAttributes(
+        Display display, IComposerClient::getReadbackBufferAttributes_cb hidl_cb) override {
+        PixelFormat format = static_cast<PixelFormat>(0);
+        Dataspace dataspace = Dataspace::UNKNOWN;
+        Error error = mHal->getReadbackBufferAttributes(display, &format, &dataspace);
+        hidl_cb(error, format, dataspace);
+        return Void();
+    }
+
+    Return<void> getReadbackBufferFence(
+        Display display, IComposerClient::getReadbackBufferFence_cb hidl_cb) override {
+        base::unique_fd fenceFd;
+        Error error = mHal->getReadbackBufferFence(display, &fenceFd);
+        if (error != Error::NONE) {
+            hidl_cb(error, nullptr);
+            return Void();
+        }
+
+        NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
+        hidl_cb(error, getFenceHandle(fenceFd, fenceStorage));
+        return Void();
+    }
+
+    Return<Error> setReadbackBuffer(Display display, const hidl_handle& buffer,
+                                    const hidl_handle& releaseFence) override {
+        base::unique_fd fenceFd;
+        Error error = getFenceFd(releaseFence, &fenceFd);
+        if (error != Error::NONE) {
+            return error;
+        }
+
+        auto resources = static_cast<ComposerResources*>(mResources.get());
+        const native_handle_t* readbackBuffer;
+        ComposerResources::ReplacedBufferHandle replacedReadbackBuffer;
+        error = resources->getDisplayReadbackBuffer(display, buffer.getNativeHandle(),
+                                                    &readbackBuffer, &replacedReadbackBuffer);
+        if (error != Error::NONE) {
+            return error;
+        }
+
+        return mHal->setReadbackBuffer(display, readbackBuffer, std::move(fenceFd));
+    }
+
+    Return<Error> setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) override {
+        return mHal->setPowerMode_2_2(display, mode);
+    }
+
+   protected:
+    std::unique_ptr<V2_1::hal::ComposerResources> createResources() override {
+        return ComposerResources::create();
+    }
+
+    std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
+        return std::make_unique<ComposerCommandEngine>(
+            mHal, static_cast<ComposerResources*>(mResources.get()));
+    }
+
+    // convert fenceFd to or from hidl_handle
+    static Error getFenceFd(const hidl_handle& fenceHandle, base::unique_fd* outFenceFd) {
+        auto handle = fenceHandle.getNativeHandle();
+        if (handle && handle->numFds > 1) {
+            ALOGE("invalid fence handle with %d fds", handle->numFds);
+            return Error::BAD_PARAMETER;
+        }
+
+        int fenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1;
+        if (fenceFd >= 0) {
+            fenceFd = dup(fenceFd);
+            if (fenceFd < 0) {
+                return Error::NO_RESOURCES;
+            }
+        }
+
+        outFenceFd->reset(fenceFd);
+
+        return Error::NONE;
+    }
+
+    static hidl_handle getFenceHandle(const base::unique_fd& fenceFd, char* handleStorage) {
+        native_handle_t* handle = nullptr;
+        if (fenceFd >= 0) {
+            handle = native_handle_init(handleStorage, 1, 0);
+            handle->data[0] = fenceFd;
+        }
+
+        return hidl_handle(handle);
+    }
+
+   private:
+    using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1::mHal;
+    using BaseType2_1::mResources;
+};
+
+}  // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+}  // 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/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
new file mode 100644
index 0000000..adcac46
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
@@ -0,0 +1,103 @@
+/*
+ * 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 "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#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>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_1::hal::ComposerCommandEngine {
+   public:
+    ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
+        : BaseType2_1(hal, resources), mHal(hal) {}
+
+   protected:
+    bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+        switch (static_cast<IComposerClient::Command>(command)) {
+            case IComposerClient::Command::SET_PER_FRAME_METADATA:
+                return executeSetPerFrameMetadata(length);
+            case IComposerClient::Command::SET_LAYER_FLOAT_COLOR:
+                return executeSetLayerFloatColor(length);
+            default:
+                return BaseType2_1::executeCommand(command, length);
+        }
+    }
+
+    bool executeSetPerFrameMetadata(uint16_t length) {
+        // (key, value) pairs
+        if (length % 2 != 0) {
+            return false;
+        }
+
+        std::vector<IComposerClient::PerFrameMetadata> metadata;
+        metadata.reserve(length / 2);
+        while (length > 0) {
+            metadata.emplace_back(IComposerClient::PerFrameMetadata{
+                static_cast<IComposerClient::PerFrameMetadataKey>(readSigned()), readFloat()});
+            length -= 2;
+        }
+
+        auto err = mHal->setPerFrameMetadata(mCurrentDisplay, metadata);
+        if (err != Error::NONE) {
+            mWriter.setError(getCommandLoc(), err);
+        }
+
+        return true;
+    }
+
+    bool executeSetLayerFloatColor(uint16_t length) {
+        if (length != CommandWriterBase::kSetLayerFloatColorLength) {
+            return false;
+        }
+
+        auto err = mHal->setLayerFloatColor(mCurrentDisplay, mCurrentLayer, readFloatColor());
+        if (err != Error::NONE) {
+            mWriter.setError(getCommandLoc(), err);
+        }
+
+        return true;
+    }
+
+    IComposerClient::FloatColor readFloatColor() {
+        return IComposerClient::FloatColor{readFloat(), readFloat(), readFloat(), readFloat()};
+    }
+
+   private:
+    using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+    using BaseType2_1::mWriter;
+
+    ComposerHal* mHal;
+};
+
+}  // 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/ComposerHal.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h
new file mode 100644
index 0000000..30b3643
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-hal/2.1/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using common::V1_0::Dataspace;
+using common::V1_0::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+
+class ComposerHal : public V2_1::hal::ComposerHal {
+   public:
+    // superceded by setPowerMode_2_2
+    Error setPowerMode(Display display, V2_1::IComposerClient::PowerMode mode) override {
+        return setPowerMode_2_2(display, static_cast<IComposerClient::PowerMode>(mode));
+    }
+
+    virtual Error getPerFrameMetadataKeys(
+        Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
+    virtual Error setPerFrameMetadata(
+        Display display, const std::vector<IComposerClient::PerFrameMetadata>& metadata) = 0;
+
+    virtual Error getReadbackBufferAttributes(Display display, PixelFormat* outFormat,
+                                              Dataspace* outDataspace) = 0;
+    virtual Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+                                    base::unique_fd fenceFd) = 0;
+    virtual Error getReadbackBufferFence(Display display, base::unique_fd* outFenceFd) = 0;
+
+    virtual Error setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) = 0;
+
+    virtual Error setLayerFloatColor(Display display, Layer layer,
+                                     IComposerClient::FloatColor color) = 0;
+};
+
+}  // 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/hal/include/composer-hal/2.2/ComposerResources.h
new file mode 100644
index 0000000..85b6651
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <composer-hal/2.1/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
+   public:
+    ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+                            uint32_t outputBufferCacheSize)
+        : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
+          mReadbackBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, 1) {}
+
+    Error 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);
+    }
+
+   protected:
+    ComposerHandleCache mReadbackBufferCache;
+};
+
+class ComposerResources : public V2_1::hal::ComposerResources {
+   public:
+    static std::unique_ptr<ComposerResources> create() {
+        auto resources = std::make_unique<ComposerResources>();
+        return resources->init() ? std::move(resources) : nullptr;
+    }
+
+    Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+                                   const native_handle_t** outHandle,
+                                   ReplacedBufferHandle* 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;
+    }
+
+   protected:
+    std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
+        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
+        return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+    }
+};
+
+}  // namespace hal
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/utils/passthrough/Android.bp b/graphics/composer/2.2/utils/passthrough/Android.bp
new file mode 100644
index 0000000..318ce91
--- /dev/null
+++ b/graphics/composer/2.2/utils/passthrough/Android.bp
@@ -0,0 +1,14 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.2-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-passthrough",
+        "android.hardware.graphics.composer@2.2-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.1-passthrough",
+        "android.hardware.graphics.composer@2.2-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
new file mode 100644
index 0000000..b251351
--- /dev/null
+++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <composer-hal/2.2/ComposerHal.h>
+#include <composer-passthrough/2.1/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_0::Dataspace;
+using common::V1_0::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_1::passthrough::detail::HwcHalImpl<Hal> {
+   public:
+    // XXX when can we return Error::UNSUPPORTED?
+
+    Error getPerFrameMetadataKeys(
+        Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override {
+        if (!mDispatch.getPerFrameMetadataKeys) {
+            return Error::UNSUPPORTED;
+        }
+
+        uint32_t count = 0;
+        int32_t error = mDispatch.getPerFrameMetadataKeys(mDevice, display, &count, nullptr);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        std::vector<IComposerClient::PerFrameMetadataKey> keys(count);
+        error = mDispatch.getPerFrameMetadataKeys(
+            mDevice, display, &count,
+            reinterpret_cast<std::underlying_type<IComposerClient::PerFrameMetadataKey>::type*>(
+                keys.data()));
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        keys.resize(count);
+        *outKeys = std::move(keys);
+        return Error::NONE;
+    }
+
+    Error setPerFrameMetadata(
+        Display display, const std::vector<IComposerClient::PerFrameMetadata>& metadata) override {
+        if (!mDispatch.setPerFrameMetadata) {
+            return Error::UNSUPPORTED;
+        }
+
+        std::vector<int32_t> keys;
+        std::vector<float> values;
+        keys.reserve(metadata.size());
+        values.reserve(metadata.size());
+        for (const auto& m : metadata) {
+            keys.push_back(static_cast<int32_t>(m.key));
+            values.push_back(m.value);
+        }
+
+        int32_t error = mDispatch.setPerFrameMetadata(mDevice, display, metadata.size(),
+                                                      keys.data(), values.data());
+        return static_cast<Error>(error);
+    }
+
+    Error getReadbackBufferAttributes(Display display, PixelFormat* outFormat,
+                                      Dataspace* outDataspace) override {
+        if (!mDispatch.getReadbackBufferAttributes) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t format = 0;
+        int32_t dataspace = 0;
+        int32_t error =
+            mDispatch.getReadbackBufferAttributes(mDevice, display, &format, &dataspace);
+        if (error == HWC2_ERROR_NONE) {
+            *outFormat = static_cast<PixelFormat>(format);
+            *outDataspace = static_cast<Dataspace>(dataspace);
+        }
+        return static_cast<Error>(error);
+    }
+
+    Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+                            base::unique_fd fenceFd) override {
+        if (!mDispatch.setReadbackBuffer) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t error =
+            mDispatch.setReadbackBuffer(mDevice, display, bufferHandle, fenceFd.release());
+        return static_cast<Error>(error);
+    }
+
+    Error getReadbackBufferFence(Display display, base::unique_fd* outFenceFd) override {
+        if (!mDispatch.getReadbackBufferFence) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t fenceFd = -1;
+        int32_t error = mDispatch.getReadbackBufferFence(mDevice, display, &fenceFd);
+        outFenceFd->reset(fenceFd);
+        return static_cast<Error>(error);
+    }
+
+    Error setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) override {
+        if (mode == IComposerClient::PowerMode::ON_SUSPEND) {
+            return Error::UNSUPPORTED;
+        }
+        return setPowerMode(display, static_cast<V2_1::IComposerClient::PowerMode>(mode));
+    }
+
+    Error setLayerFloatColor(Display display, Layer layer,
+                             IComposerClient::FloatColor color) override {
+        if (!mDispatch.setLayerFloatColor) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t error = mDispatch.setLayerFloatColor(
+            mDevice, display, layer, hwc_float_color{color.r, color.g, color.b, color.a});
+        return static_cast<Error>(error);
+    }
+
+   protected:
+    template <typename T>
+    bool initOptionalDispatch(hwc2_function_descriptor_t desc, T* outPfn) {
+        auto pfn = mDevice->getFunction(mDevice, desc);
+        if (pfn) {
+            *outPfn = reinterpret_cast<T>(pfn);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool initDispatch() override {
+        if (!BaseType2_1::initDispatch()) {
+            return false;
+        }
+
+        initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_FLOAT_COLOR, &mDispatch.setLayerFloatColor);
+
+        initOptionalDispatch(HWC2_FUNCTION_SET_PER_FRAME_METADATA, &mDispatch.setPerFrameMetadata);
+        initOptionalDispatch(HWC2_FUNCTION_GET_PER_FRAME_METADATA_KEYS,
+                             &mDispatch.getPerFrameMetadataKeys);
+
+        initOptionalDispatch(HWC2_FUNCTION_SET_READBACK_BUFFER, &mDispatch.setReadbackBuffer);
+        initOptionalDispatch(HWC2_FUNCTION_GET_READBACK_BUFFER_ATTRIBUTES,
+                             &mDispatch.getReadbackBufferAttributes);
+        initOptionalDispatch(HWC2_FUNCTION_GET_READBACK_BUFFER_FENCE,
+                             &mDispatch.getReadbackBufferFence);
+
+        return true;
+    }
+
+    struct {
+        HWC2_PFN_SET_LAYER_FLOAT_COLOR setLayerFloatColor;
+        HWC2_PFN_SET_PER_FRAME_METADATA setPerFrameMetadata;
+        HWC2_PFN_GET_PER_FRAME_METADATA_KEYS getPerFrameMetadataKeys;
+        HWC2_PFN_SET_READBACK_BUFFER setReadbackBuffer;
+        HWC2_PFN_GET_READBACK_BUFFER_ATTRIBUTES getReadbackBufferAttributes;
+        HWC2_PFN_GET_READBACK_BUFFER_FENCE getReadbackBufferFence;
+    } mDispatch = {};
+
+   private:
+    using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1::mDevice;
+    using BaseType2_1::setPowerMode;
+};
+
+}  // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+}  // namespace passthrough
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcLoader.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcLoader.h
new file mode 100644
index 0000000..cb4a238
--- /dev/null
+++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.2/Composer.h>
+#include <composer-hal/2.2/ComposerHal.h>
+#include <composer-passthrough/2.1/HwcLoader.h>
+#include <composer-passthrough/2.2/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace passthrough {
+
+class HwcLoader : public V2_1::passthrough::HwcLoader {
+   public:
+    static IComposer* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+
+        auto hal = createHalWithAdapter(module);
+        if (!hal) {
+            return nullptr;
+        }
+
+        return createComposer(std::move(hal)).release();
+    }
+
+    // create a ComposerHal instance
+    static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithModule(module) ? std::move(hal) : nullptr;
+    }
+
+    // create a ComposerHal instance, insert an adapter if necessary
+    static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+        bool adapted;
+        hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+        if (!device) {
+            return nullptr;
+        }
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+    }
+
+    // create an IComposer instance
+    static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+        return hal::Composer::create(std::move(hal));
+    }
+};
+
+}  // namespace passthrough
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android