Merge "media: update VP9 CodecProfileLevel" into nyc-dev
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 2bfea63..5481313 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -1304,13 +1304,17 @@
     return true;
 }
 
-static int open_output_file(char* file_name, bool recreate) {
+static int open_output_file(char* file_name, bool recreate, int permissions) {
     int flags = O_RDWR | O_CREAT;
     if (recreate) {
-        unlink(file_name);
+        if (unlink(file_name) < 0) {
+            if (errno != ENOENT) {
+                PLOG(ERROR) << "open_output_file: Couldn't unlink " << file_name;
+            }
+        }
         flags |= O_EXCL;
     }
-    return open(file_name, flags, 0600);
+    return open(file_name, flags, permissions);
 }
 
 static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) {
@@ -1427,8 +1431,7 @@
         return -1;
     }
 
-    unlink(out_path);
-    out_fd = open(out_path, O_RDWR | O_CREAT | O_EXCL, 0644);
+    out_fd = open_output_file(out_path, /*recreate*/true, /*permissions*/0644);
     if (out_fd < 0) {
         ALOGE("installd cannot open '%s' for output during dexopt\n", out_path);
         goto fail;
@@ -1442,7 +1445,7 @@
         // Make sure there really is enough space.
         strcpy(swap_file_name, out_path);
         if (add_extension_to_file_name(swap_file_name, ".swap")) {
-            swap_fd = open_output_file(swap_file_name, /*recreate*/true);
+            swap_fd = open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600);
         }
         if (swap_fd < 0) {
             // Could not create swap file. Optimistically go on and hope that we can compile
@@ -1450,7 +1453,9 @@
             ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
         } else {
             // Immediately unlink. We don't really want to hit flash.
-            unlink(swap_file_name);
+            if (unlink(swap_file_name) < 0) {
+                PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
+            }
         }
     }
 
@@ -1466,7 +1471,7 @@
       if (profile_guided && have_app_image_format) {
           // Recreate is true since we do not want to modify a mapped image. If the app is already
           // running and we modify the image file, it can cause crashes (b/27493510).
-          image_fd = open_output_file(image_path, /*recreate*/true);
+          image_fd = open_output_file(image_path, /*recreate*/true, /*permissions*/0600);
           if (image_fd < 0) {
               // Could not create application image file. Go on since we can compile without it.
               ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
@@ -1476,7 +1481,11 @@
       }
       // If we have a valid image file path but no image fd, erase the image file.
       if (image_fd < 0) {
-          unlink(image_path);
+          if (unlink(image_path) < 0) {
+              if (errno != ENOENT) {
+                  PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+              }
+          }
       }
     }
 
diff --git a/include/batteryservice/BatteryService.h b/include/batteryservice/BatteryService.h
index 912dcf6..b399905 100644
--- a/include/batteryservice/BatteryService.h
+++ b/include/batteryservice/BatteryService.h
@@ -68,6 +68,7 @@
     int batteryCurrent;
     int batteryCycleCount;
     int batteryFullCharge;
+    int batteryChargeCounter;
     String8 batteryTechnology;
 
     status_t writeToParcel(Parcel* parcel) const;
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 8c3d49e..af26721 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -39,6 +39,7 @@
 class DisplayState;
 struct DisplayInfo;
 struct DisplayStatInfo;
+class HdrCapabilities;
 class IDisplayEventConnection;
 class IMemoryHeap;
 class Rect;
@@ -157,6 +158,13 @@
      * Requires the ACCESS_SURFACE_FLINGER permission.
      */
     virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
+
+    /* Gets the supported HDR capabilities of the given display.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -184,6 +192,7 @@
         GET_ANIMATION_FRAME_STATS,
         SET_POWER_MODE,
         GET_DISPLAY_STATS,
+        GET_HDR_CAPABILITIES,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 794fe4c..9161dbb 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -40,6 +40,7 @@
 
 class DisplayInfo;
 class Composer;
+class HdrCapabilities;
 class ISurfaceComposerClient;
 class IGraphicBufferProducer;
 class Region;
@@ -145,6 +146,9 @@
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
+    static status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities);
+
     static void setDisplaySurface(const sp<IBinder>& token,
             const sp<IGraphicBufferProducer>& bufferProducer);
     static void setDisplayLayerStack(const sp<IBinder>& token,
diff --git a/include/ui/HdrCapabilities.h b/include/ui/HdrCapabilities.h
new file mode 100644
index 0000000..a7cd5fb
--- /dev/null
+++ b/include/ui/HdrCapabilities.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 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_UI_HDR_CAPABILTIES_H
+#define ANDROID_UI_HDR_CAPABILTIES_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+class HdrCapabilities : public Parcelable
+{
+public:
+    HdrCapabilities(const std::vector<int32_t /*android_hdr_t*/>& types,
+            float maxLuminance, float maxAverageLuminance, float minLuminance)
+      : mSupportedHdrTypes(types),
+        mMaxLuminance(maxLuminance),
+        mMaxAverageLuminance(maxAverageLuminance),
+        mMinLuminance(minLuminance) {}
+
+    // Make this move-constructable and move-assignable
+    HdrCapabilities(HdrCapabilities&& other) = default;
+    HdrCapabilities& operator=(HdrCapabilities&& other) = default;
+
+    HdrCapabilities()
+      : mSupportedHdrTypes(),
+        mMaxLuminance(-1.0f),
+        mMaxAverageLuminance(-1.0f),
+        mMinLuminance(-1.0f) {}
+
+    virtual ~HdrCapabilities() = default;
+
+    const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const {
+        return mSupportedHdrTypes;
+    }
+    float getDesiredMaxLuminance() const { return mMaxLuminance; }
+    float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; }
+    float getDesiredMinLuminance() const { return mMinLuminance; }
+
+    // Parcelable interface
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+private:
+    std::vector<int32_t /*android_hdr_t*/> mSupportedHdrTypes;
+    float mMaxLuminance;
+    float mMaxAverageLuminance;
+    float mMinLuminance;
+};
+
+} // namespace android
+
+#endif
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index b4cbf84..a8b4fa8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -34,6 +34,7 @@
 
 #include <ui/DisplayInfo.h>
 #include <ui/DisplayStatInfo.h>
+#include <ui/HdrCapabilities.h>
 
 #include <utils/Log.h>
 
@@ -282,6 +283,28 @@
         reply.read(*outStats);
         return reply.readInt32();
     }
+
+    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        status_t result = data.writeStrongBinder(display);
+        if (result != NO_ERROR) {
+            ALOGE("getHdrCapabilities failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::GET_HDR_CAPABILITIES,
+                data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getHdrCapabilities failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32();
+        if (result == NO_ERROR) {
+            result = reply.readParcelable(outCapabilities);
+        }
+        return result;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -467,6 +490,23 @@
             setPowerMode(display, mode);
             return NO_ERROR;
         }
+        case GET_HDR_CAPABILITIES: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> display = nullptr;
+            status_t result = data.readStrongBinder(&display);
+            if (result != NO_ERROR) {
+                ALOGE("getHdrCapabilities failed to readStrongBinder: %d",
+                        result);
+                return result;
+            }
+            HdrCapabilities capabilities;
+            result = getHdrCapabilities(display, &capabilities);
+            reply->writeInt32(result);
+            if (result == NO_ERROR) {
+                reply->writeParcelable(capabilities);
+            }
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 04b5446..f031296 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -291,9 +291,6 @@
     s->w = w;
     s->h = h;
 
-    // Resizing a surface makes the transaction synchronous.
-    mForceSynchronous = true;
-
     return NO_ERROR;
 }
 
@@ -454,7 +451,6 @@
     s.viewport = layerStackRect;
     s.frame = displayRect;
     s.what |= DisplayState::eDisplayProjectionChanged;
-    mForceSynchronous = true; // TODO: do we actually still need this?
 }
 
 void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
@@ -722,6 +718,12 @@
     return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
 }
 
+status_t SurfaceComposerClient::getHdrCapabilities(const sp<IBinder>& display,
+        HdrCapabilities* outCapabilities) {
+    return ComposerService::getComposerService()->getHdrCapabilities(display,
+            outCapabilities);
+}
+
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index e4cdcab..ee6c093 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -40,12 +40,14 @@
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
 	GraphicBufferMapper.cpp \
+	HdrCapabilities.cpp \
 	PixelFormat.cpp \
 	Rect.cpp \
 	Region.cpp \
 	UiConfig.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+	libbinder \
 	libcutils \
 	libhardware \
 	libsync \
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
new file mode 100644
index 0000000..511f68a
--- /dev/null
+++ b/libs/ui/HdrCapabilities.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 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 <ui/HdrCapabilities.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+status_t HdrCapabilities::writeToParcel(Parcel* parcel) const
+{
+    status_t result = parcel->writeInt32Vector(mSupportedHdrTypes);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeFloat(mMaxLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeFloat(mMaxAverageLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeFloat(mMinLuminance);
+    return result;
+}
+
+status_t HdrCapabilities::readFromParcel(const Parcel* parcel)
+{
+    status_t result = parcel->readInt32Vector(&mSupportedHdrTypes);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->readFloat(&mMaxLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->readFloat(&mMaxAverageLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->readFloat(&mMinLuminance);
+    return result;
+}
+
+} // namespace android
diff --git a/services/batteryservice/BatteryProperties.cpp b/services/batteryservice/BatteryProperties.cpp
index 07cc797..d89d4c9 100644
--- a/services/batteryservice/BatteryProperties.cpp
+++ b/services/batteryservice/BatteryProperties.cpp
@@ -41,6 +41,7 @@
     batteryLevel = p->readInt32();
     batteryVoltage = p->readInt32();
     batteryTemperature = p->readInt32();
+    batteryChargeCounter = p->readInt32();
     batteryTechnology = String8((p->readString16()).string());
     return OK;
 }
@@ -57,6 +58,7 @@
     p->writeInt32(batteryLevel);
     p->writeInt32(batteryVoltage);
     p->writeInt32(batteryTemperature);
+    p->writeInt32(batteryChargeCounter);
     p->writeString16(String16(batteryTechnology));
     return OK;
 }
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8556c23..374a5de 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -697,6 +697,21 @@
     return result;
 }
 
+void InputReader::toggleCapsLockState(int32_t deviceId) {
+    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+    if (deviceIndex < 0) {
+        ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId);
+        return;
+    }
+
+    InputDevice* device = mDevices.valueAt(deviceIndex);
+    if (device->isIgnored()) {
+        return;
+    }
+
+    device->updateMetaState(AKEYCODE_CAPS_LOCK);
+}
+
 bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask,
         size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
     AutoMutex _l(mLock);
@@ -1172,6 +1187,13 @@
     return result;
 }
 
+void InputDevice::updateMetaState(int32_t keyCode) {
+    size_t numMappers = mMappers.size();
+    for (size_t i = 0; i < numMappers; i++) {
+        mMappers[i]->updateMetaState(keyCode);
+    }
+}
+
 void InputDevice::fadePointer() {
     size_t numMappers = mMappers.size();
     for (size_t i = 0; i < numMappers; i++) {
@@ -1880,6 +1902,9 @@
     return 0;
 }
 
+void InputMapper::updateMetaState(int32_t keyCode) {
+}
+
 void InputMapper::updateExternalStylusState(const StylusState& state) {
 
 }
@@ -2265,18 +2290,12 @@
         }
     }
 
-    int32_t oldMetaState = mMetaState;
-    int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
-    bool metaStateChanged = oldMetaState != newMetaState;
-    if (metaStateChanged) {
-        mMetaState = newMetaState;
-        updateLedState(false);
-
+    if (updateMetaStateIfNeeded(keyCode, down)) {
         // If global meta state changed send it along with the key.
         // If it has not changed then we'll use what keymap gave us,
         // since key replacement logic might temporarily reset a few
         // meta bits for given key.
-        keyMetaState = newMetaState;
+        keyMetaState = mMetaState;
     }
 
     nsecs_t downTime = mDownTime;
@@ -2294,10 +2313,6 @@
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
 
-    if (metaStateChanged) {
-        getContext()->updateGlobalMetaState();
-    }
-
     if (down && !isMetaKey(keyCode)) {
         getContext()->fadePointer();
     }
@@ -2335,6 +2350,24 @@
     return mMetaState;
 }
 
+void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
+    updateMetaStateIfNeeded(keyCode, false);
+}
+
+bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
+    int32_t oldMetaState = mMetaState;
+    int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState);
+    bool metaStateChanged = oldMetaState != newMetaState;
+    if (metaStateChanged) {
+        mMetaState = newMetaState;
+        updateLedState(false);
+
+        getContext()->updateGlobalMetaState();
+    }
+
+    return metaStateChanged;
+}
+
 void KeyboardInputMapper::resetLedState() {
     initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
     initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index e554e57..076f3d6 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -359,6 +359,9 @@
     virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
             int32_t sw) = 0;
 
+    /* Toggle Caps Lock */
+    virtual void toggleCapsLockState(int32_t deviceId) = 0;
+
     /* Determine whether physical keys exist for the given framework-domain key codes. */
     virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
             size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
@@ -461,6 +464,8 @@
     virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
             int32_t sw);
 
+    virtual void toggleCapsLockState(int32_t deviceId);
+
     virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
             size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);
 
@@ -616,6 +621,7 @@
     void cancelTouch(nsecs_t when);
 
     int32_t getMetaState();
+    void updateMetaState(int32_t keyCode);
 
     void fadePointer();
 
@@ -1031,6 +1037,7 @@
     virtual void cancelTouch(nsecs_t when);
 
     virtual int32_t getMetaState();
+    virtual void updateMetaState(int32_t keyCode);
 
     virtual void updateExternalStylusState(const StylusState& state);
 
@@ -1116,6 +1123,7 @@
             const int32_t* keyCodes, uint8_t* outFlags);
 
     virtual int32_t getMetaState();
+    virtual void updateMetaState(int32_t keyCode);
 
 private:
     struct KeyDown {
@@ -1156,6 +1164,8 @@
 
     void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
 
+    bool updateMetaStateIfNeeded(int32_t keyCode, bool down);
+
     ssize_t findKeyDown(int32_t scanCode);
 
     void resetLedState();
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 44a3334..fb6307e 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -12,6 +12,7 @@
     EventThread.cpp \
     FenceTracker.cpp \
     FrameTracker.cpp \
+    GpuService.cpp \
     Layer.cpp \
     LayerDim.cpp \
     MessageQueue.cpp \
@@ -37,6 +38,9 @@
     RenderEngine/GLES11RenderEngine.cpp \
     RenderEngine/GLES20RenderEngine.cpp
 
+LOCAL_C_INCLUDES := \
+	frameworks/native/vulkan/include \
+	external/vulkan-validation-layers/libs/vkjson
 
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
@@ -106,6 +110,7 @@
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
 LOCAL_CFLAGS += -std=c++14
 
+LOCAL_STATIC_LIBRARIES := libvkjson
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     liblog \
@@ -118,7 +123,8 @@
     libbinder \
     libui \
     libgui \
-    libpowermanager
+    libpowermanager \
+    libvulkan
 
 LOCAL_MODULE := libsurfaceflinger
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 0e97a53..5c78c68 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -74,6 +74,7 @@
 using android::Fence;
 using android::FloatRect;
 using android::GraphicBuffer;
+using android::HdrCapabilities;
 using android::Rect;
 using android::Region;
 using android::sp;
@@ -100,6 +101,7 @@
     mGetDisplayRequests(nullptr),
     mGetDisplayType(nullptr),
     mGetDozeSupport(nullptr),
+    mGetHdrCapabilities(nullptr),
     mGetReleaseFences(nullptr),
     mPresentDisplay(nullptr),
     mSetActiveConfig(nullptr),
@@ -307,82 +309,84 @@
     // loadFunctionPointer specifying which function failed to load
 
     // Display function pointers
-    if(!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay,
             mCreateVirtualDisplay)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay,
             mDestroyVirtualDisplay)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount,
+    if (!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return;
+    if (!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount,
             mGetMaxVirtualDisplayCount)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::RegisterCallback,
+    if (!loadFunctionPointer(FunctionDescriptor::RegisterCallback,
             mRegisterCallback)) return;
 
     // Device function pointers
-    if(!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges,
+    if (!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges,
             mAcceptDisplayChanges)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::CreateLayer,
+    if (!loadFunctionPointer(FunctionDescriptor::CreateLayer,
             mCreateLayer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::DestroyLayer,
+    if (!loadFunctionPointer(FunctionDescriptor::DestroyLayer,
             mDestroyLayer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetActiveConfig,
+    if (!loadFunctionPointer(FunctionDescriptor::GetActiveConfig,
             mGetActiveConfig)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes,
+    if (!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes,
             mGetChangedCompositionTypes)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute,
             mGetDisplayAttribute)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs,
             mGetDisplayConfigs)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayName,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayName,
             mGetDisplayName)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests,
             mGetDisplayRequests)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayType,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayType,
             mGetDisplayType)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDozeSupport,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDozeSupport,
             mGetDozeSupport)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetReleaseFences,
+    if (!loadFunctionPointer(FunctionDescriptor::GetHdrCapabilities,
+            mGetHdrCapabilities)) return;
+    if (!loadFunctionPointer(FunctionDescriptor::GetReleaseFences,
             mGetReleaseFences)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::PresentDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::PresentDisplay,
             mPresentDisplay)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetActiveConfig,
+    if (!loadFunctionPointer(FunctionDescriptor::SetActiveConfig,
             mSetActiveConfig)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetClientTarget,
+    if (!loadFunctionPointer(FunctionDescriptor::SetClientTarget,
             mSetClientTarget)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer,
+    if (!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer,
             mSetOutputBuffer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetPowerMode,
+    if (!loadFunctionPointer(FunctionDescriptor::SetPowerMode,
             mSetPowerMode)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled,
+    if (!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled,
             mSetVsyncEnabled)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::ValidateDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::ValidateDisplay,
             mValidateDisplay)) return;
 
     // Layer function pointers
-    if(!loadFunctionPointer(FunctionDescriptor::SetCursorPosition,
+    if (!loadFunctionPointer(FunctionDescriptor::SetCursorPosition,
             mSetCursorPosition)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer,
             mSetLayerBuffer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage,
             mSetLayerSurfaceDamage)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode,
             mSetLayerBlendMode)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerColor,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerColor,
             mSetLayerColor)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType,
             mSetLayerCompositionType)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame,
             mSetLayerDisplayFrame)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha,
             mSetLayerPlaneAlpha)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream,
             mSetLayerSidebandStream)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop,
             mSetLayerSourceCrop)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerTransform,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerTransform,
             mSetLayerTransform)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion,
             mSetLayerVisibleRegion)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
             mSetLayerZOrder)) return;
 }
 
@@ -637,6 +641,34 @@
     return Error::None;
 }
 
+Error Display::getHdrCapabilities(
+        std::unique_ptr<HdrCapabilities>* outCapabilities) const
+{
+    uint32_t numTypes = 0;
+    float maxLuminance = -1.0f;
+    float maxAverageLuminance = -1.0f;
+    float minLuminance = -1.0f;
+    int32_t intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId,
+            &numTypes, nullptr, &maxLuminance, &maxAverageLuminance,
+            &minLuminance);
+    auto error = static_cast<HWC2::Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    std::vector<int32_t> types(numTypes);
+    intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, &numTypes,
+            types.data(), &maxLuminance, &maxAverageLuminance, &minLuminance);
+    error = static_cast<HWC2::Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    *outCapabilities = std::make_unique<HdrCapabilities>(std::move(types),
+            maxLuminance, maxAverageLuminance, minLuminance);
+    return Error::None;
+}
+
 Error Display::getReleaseFences(
         std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
 {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a7bd28c..7d33a0a 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,6 +23,8 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
+#include <ui/HdrCapabilities.h>
+
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
@@ -145,6 +147,7 @@
     HWC2_PFN_GET_DISPLAY_REQUESTS mGetDisplayRequests;
     HWC2_PFN_GET_DISPLAY_TYPE mGetDisplayType;
     HWC2_PFN_GET_DOZE_SUPPORT mGetDozeSupport;
+    HWC2_PFN_GET_HDR_CAPABILITIES mGetHdrCapabilities;
     HWC2_PFN_GET_RELEASE_FENCES mGetReleaseFences;
     HWC2_PFN_PRESENT_DISPLAY mPresentDisplay;
     HWC2_PFN_SET_ACTIVE_CONFIG mSetActiveConfig;
@@ -279,6 +282,8 @@
                     outLayerRequests);
     [[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
     [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
+    [[clang::warn_unused_result]] Error getHdrCapabilities(
+            std::unique_ptr<android::HdrCapabilities>* outCapabilities) const;
     [[clang::warn_unused_result]] Error getReleaseFences(
             std::unordered_map<std::shared_ptr<Layer>,
                     android::sp<android::Fence>>* outFences) const;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index dabc77f..6ebcdfe 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -238,6 +238,11 @@
             return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
                     displayHook<decltype(&Display::getDozeSupport),
                     &Display::getDozeSupport, int32_t*>);
+        case FunctionDescriptor::GetHdrCapabilities:
+            return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
+                    displayHook<decltype(&Display::getHdrCapabilities),
+                    &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
+                    float*, float*>);
         case FunctionDescriptor::GetReleaseFences:
             return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
                     displayHook<decltype(&Display::getReleaseFences),
@@ -709,6 +714,15 @@
     return Error::None;
 }
 
+Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes,
+        int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+        float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/)
+{
+    // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
+    *outNumTypes = 0;
+    return Error::None;
+}
+
 Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName)
 {
     std::unique_lock<std::recursive_mutex> lock(mStateMutex);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
index bffeefe..6fdb184 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -194,6 +194,9 @@
             HWC2::Error getConfigs(uint32_t* outNumConfigs,
                     hwc2_config_t* outConfigIds);
             HWC2::Error getDozeSupport(int32_t* outSupport);
+            HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
+                    int32_t* outTypes, float* outMaxLuminance,
+                    float* outMaxAverageLuminance, float* outMinLuminance);
             HWC2::Error getName(uint32_t* outSize, char* outName);
             HWC2::Error getReleaseFences(uint32_t* outNumElements,
                     hwc2_layer_t* outLayers, int32_t* outFences);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 26f9519..cd2e05f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -736,6 +736,26 @@
     mDisplayData[displayId].releaseFences.clear();
 }
 
+std::unique_ptr<HdrCapabilities> HWComposer::getHdrCapabilities(
+        int32_t displayId) {
+    if (!isValidDisplay(displayId)) {
+        ALOGE("getHdrCapabilities: Display %d is not valid", displayId);
+        return nullptr;
+    }
+
+    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+    std::unique_ptr<HdrCapabilities> capabilities;
+    auto error = hwcDisplay->getHdrCapabilities(&capabilities);
+    if (error != HWC2::Error::None) {
+        ALOGE("getOutputCapabilities: Failed to get capabilities on display %d:"
+                " %s (%d)", displayId, to_string(error).c_str(),
+                static_cast<int32_t>(error));
+        return nullptr;
+    }
+
+    return capabilities;
+}
+
 // Converts a PixelFormat to a human-readable string.  Max 11 chars.
 // (Could use a table of prefab String8 objects.)
 /*
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 30c8f67..d407877 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -130,6 +130,9 @@
     // it can call this to clear the shared pointers in the release fence map
     void clearReleaseFences(int32_t displayId);
 
+    // Returns the HDR capabilities of the given display
+    std::unique_ptr<HdrCapabilities> getHdrCapabilities(int32_t displayId);
+
     // Events handling ---------------------------------------------------------
 
     void setVsyncEnabled(int32_t disp, HWC2::Vsync enabled);
diff --git a/services/surfaceflinger/GpuService.cpp b/services/surfaceflinger/GpuService.cpp
new file mode 100644
index 0000000..0c29971
--- /dev/null
+++ b/services/surfaceflinger/GpuService.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2016 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 "GpuService.h"
+
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <vkjson.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class BpGpuService : public BpInterface<IGpuService>
+{
+public:
+    BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
+};
+
+IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
+
+status_t BnGpuService::onTransact(uint32_t code, const Parcel& data,
+        Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+    case SHELL_COMMAND_TRANSACTION: {
+        int in = data.readFileDescriptor();
+        int out = data.readFileDescriptor();
+        int err = data.readFileDescriptor();
+        int argc = data.readInt32();
+        Vector<String16> args;
+        for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+           args.add(data.readString16());
+        }
+        return shellCommand(in, out, err, args);
+    }
+
+    default:
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+    status_t cmd_help(int out);
+    status_t cmd_vkjson(int out, int err);
+}
+
+const char* const GpuService::SERVICE_NAME = "gpu";
+
+GpuService::GpuService() {}
+
+status_t GpuService::shellCommand(int /*in*/, int out, int err,
+        Vector<String16>& args)
+{
+    ALOGV("GpuService::shellCommand");
+    for (size_t i = 0, n = args.size(); i < n; i++)
+        ALOGV("  arg[%zu]: '%s'", i, String8(args[i]).string());
+
+    if (args[0] == String16("vkjson"))
+        return cmd_vkjson(out, err);
+    else if (args[0] == String16("help"))
+        return cmd_help(out);
+
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+status_t cmd_help(int out) {
+    FILE* outs = fdopen(out, "w");
+    if (!outs) {
+        ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno),
+            errno);
+        return BAD_VALUE;
+    }
+    fprintf(outs,
+        "GPU Service commands:\n"
+        "  vkjson   dump Vulkan device capabilities as JSON\n");
+    fclose(outs);
+    return NO_ERROR;
+}
+
+VkResult vkjsonPrint(FILE* out, FILE* err) {
+    VkResult result;
+
+    const VkApplicationInfo app_info = {
+        VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr,
+        "vkjson", 1,    /* app name, version */
+        "", 0,          /* engine name, version */
+        VK_API_VERSION
+    };
+    const VkInstanceCreateInfo instance_info = {
+        VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, nullptr,
+        0,              /* flags */
+        &app_info,
+        0, nullptr,     /* layers */
+        0, nullptr,     /* extensions */
+    };
+    VkInstance instance;
+    result = vkCreateInstance(&instance_info, nullptr, &instance);
+    if (result != VK_SUCCESS) {
+        fprintf(err, "vkCreateInstance failed: %d\n", result);
+        return result;
+    }
+
+    uint32_t ngpu = 0;
+    result = vkEnumeratePhysicalDevices(instance, &ngpu, nullptr);
+    if (result != VK_SUCCESS) {
+        fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result);
+        return result;
+    }
+    std::vector<VkPhysicalDevice> gpus(ngpu, VK_NULL_HANDLE);
+    result = vkEnumeratePhysicalDevices(instance, &ngpu, gpus.data());
+    if (result != VK_SUCCESS) {
+        fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result);
+        return result;
+    }
+
+    for (size_t i = 0, n = gpus.size(); i < n; i++) {
+        auto props = VkJsonGetAllProperties(gpus[i]);
+        std::string json = VkJsonAllPropertiesToJson(props);
+        fwrite(json.data(), 1, json.size(), out);
+        if (i < n - 1)
+            fputc(',', out);
+        fputc('\n', out);
+    }
+
+    vkDestroyInstance(instance, nullptr);
+
+    return VK_SUCCESS;
+}
+
+status_t cmd_vkjson(int out, int err) {
+    int errnum;
+    FILE* outs = fdopen(out, "w");
+    if (!outs) {
+        errnum = errno;
+        ALOGE("vkjson: failed to create output stream: %s", strerror(errnum));
+        return -errnum;
+    }
+    FILE* errs = fdopen(err, "w");
+    if (!errs) {
+        errnum = errno;
+        ALOGE("vkjson: failed to create error stream: %s", strerror(errnum));
+        fclose(outs);
+        return -errnum;
+    }
+    fprintf(outs, "[\n");
+    VkResult result = vkjsonPrint(outs, errs);
+    fprintf(outs, "]\n");
+    fclose(errs);
+    fclose(outs);
+    return result >= 0 ? NO_ERROR : UNKNOWN_ERROR;
+}
+
+} // anonymous namespace
+
+} // namespace android
diff --git a/services/surfaceflinger/GpuService.h b/services/surfaceflinger/GpuService.h
new file mode 100644
index 0000000..b8c28d2
--- /dev/null
+++ b/services/surfaceflinger/GpuService.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 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_GPUSERVICE_H
+#define ANDROID_GPUSERVICE_H
+
+#include <binder/IInterface.h>
+#include <cutils/compiler.h>
+
+namespace android {
+
+/*
+ * This class defines the Binder IPC interface for GPU-related queries and
+ * control.
+ */
+class IGpuService : public IInterface {
+public:
+    DECLARE_META_INTERFACE(GpuService);
+};
+
+class BnGpuService: public BnInterface<IGpuService> {
+protected:
+    virtual status_t shellCommand(int in, int out, int err,
+        Vector<String16>& args) = 0;
+
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags = 0) override;
+};
+
+class GpuService : public BnGpuService
+{
+public:
+    static const char* const SERVICE_NAME ANDROID_API;
+
+    GpuService() ANDROID_API;
+
+protected:
+    virtual status_t shellCommand(int in, int out, int err,
+        Vector<String16>& args) override;
+};
+
+} // namespace android
+
+#endif // ANDROID_GPUSERVICE_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ea9fe21..1f85bee 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -715,6 +715,27 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
+        HdrCapabilities* outCapabilities) const {
+    Mutex::Autolock _l(mStateLock);
+
+    sp<const DisplayDevice> displayDevice(getDisplayDevice(display));
+    if (displayDevice == nullptr) {
+        ALOGE("getHdrCapabilities: Invalid display %p", displayDevice.get());
+        return BAD_VALUE;
+    }
+
+    std::unique_ptr<HdrCapabilities> capabilities =
+            mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
+    if (capabilities) {
+        std::swap(*outCapabilities, *capabilities);
+    } else {
+        return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -1248,6 +1269,7 @@
         if (hwcId >= 0) {
             mHwc->commit(hwcId);
         }
+        displayDevice->onSwapBuffersCompleted();
         if (displayId == 0) {
             // Make the default display current because the VirtualDisplayDevice
             // code cannot deal with dequeueBuffer() being called outside of the
@@ -1255,7 +1277,6 @@
             // is allowed to (and does in some case) call dequeueBuffer().
             displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
         }
-        displayDevice->onSwapBuffersCompleted();
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             sp<Fence> releaseFence = Fence::NO_FENCE;
             if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
@@ -2881,6 +2902,7 @@
         case CLEAR_ANIMATION_FRAME_STATS:
         case GET_ANIMATION_FRAME_STATS:
         case SET_POWER_MODE:
+        case GET_HDR_CAPABILITIES:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 37110b9..8c974d0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -222,6 +222,8 @@
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id);
     virtual status_t clearAnimationFrameStats();
     virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
+    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities) const;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a63ec50..e9b3d99 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -45,6 +45,7 @@
 #include <gui/GraphicBufferAlloc.h>
 
 #include <ui/GraphicBufferAllocator.h>
+#include <ui/HdrCapabilities.h>
 #include <ui/PixelFormat.h>
 #include <ui/UiConfig.h>
 
@@ -748,6 +749,13 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& /*display*/,
+        HdrCapabilities* outCapabilities) const {
+    // HWC1 does not provide HDR capabilities
+    *outCapabilities = HdrCapabilities();
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -2917,6 +2925,7 @@
         case CLEAR_ANIMATION_FRAME_STATS:
         case GET_ANIMATION_FRAME_STATS:
         case SET_POWER_MODE:
+        case GET_HDR_CAPABILITIES:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 4cd7aeb..97a1e8b 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -21,6 +21,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
+#include "GpuService.h"
 #include "SurfaceFlinger.h"
 
 using namespace android;
@@ -56,7 +57,11 @@
     sp<IServiceManager> sm(defaultServiceManager());
     sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
 
-    // run in this thread
+    // publish GpuService
+    sp<GpuService> gpuservice = new GpuService();
+    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
+
+    // run surface flinger in this thread
     flinger->run();
 
     return 0;