Merge changes I2b89dce1,I5412eae0,I2e428ec1 into pi-dev am: 990cc3e31d
am: d828b8f5f5

Change-Id: I5f8173f6cb7505355d4d89f554d0e6389e1ed384
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 5a029d0..c2bf97e 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -85,6 +85,7 @@
     OMX_IndexParamMaxFrameDurationForBitrateControl,/**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexParamVideoVp9,                         /**< reference: OMX_VIDEO_PARAM_VP9TYPE */
     OMX_IndexParamVideoAndroidVp9Encoder,           /**< reference: OMX_VIDEO_PARAM_ANDROID_VP9ENCODERTYPE */
+    OMX_IndexParamVideoAndroidImageGrid,            /**< reference: OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE */
     OMX_IndexExtVideoEndUnused,
 
     /* Image & Video common configurations */
diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
index dc5cdab..9fd2fd2 100644
--- a/headers/media_plugin/media/openmax/OMX_Video.h
+++ b/headers/media_plugin/media/openmax/OMX_Video.h
@@ -89,6 +89,7 @@
     OMX_VIDEO_CodingVP9,        /**< Google VP9 */
     OMX_VIDEO_CodingHEVC,       /**< ITU H.265/HEVC */
     OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */
+    OMX_VIDEO_CodingImageHEIC,  /**< HEIF image encoded with HEVC */
     OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_VIDEO_CodingMax = 0x7FFFFFFF
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index c102564..4b90765 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -213,6 +213,7 @@
     OMX_VIDEO_HEVCProfileUnknown      = 0x0,
     OMX_VIDEO_HEVCProfileMain         = 0x1,
     OMX_VIDEO_HEVCProfileMain10       = 0x2,
+    OMX_VIDEO_HEVCProfileMainStill    = 0x4,
     // Main10 profile with HDR SEI support.
     OMX_VIDEO_HEVCProfileMain10HDR10  = 0x1000,
     OMX_VIDEO_HEVCProfileMax          = 0x7FFFFFFF
@@ -421,6 +422,48 @@
     OMX_U32 nBitrateRatios[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
 } OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE;
 
+/**
+ * Android specific param for specifying image grid layout information for image encoding
+ * use cases, corresponding to index OMX_IndexParamVideoAndroidImageGrid.
+ *
+ * OMX_VIDEO_CodingImageHEIC encoders must handle this param type. When this param is set
+ * on the component with bEnabled set to true, nGrid* indicates the desired grid config
+ * by the client. The component can use this as a heuristic, but is free to choose any
+ * suitable grid configs, and the client shall always get the actual from the component
+ * after the param is set. Encoder will receive each input image in full, and shall encode
+ * it into tiles in row-major, top-row first, left-to-right order, and send each encoded
+ * tile in a separate output buffer. All output buffers for the same input buffer shall
+ * carry the same timestamp as the input buffer. If the input buffer is marked EOS,
+ * the EOS should only appear on the last output buffer for that input buffer.
+ *
+ * OMX_VIDEO_CodingHEVC encoders might also receive this param when it's used for image
+ * encoding, although in this case the param only serves as a hint. The encoder will
+ * receive the input image tiles in row-major, top-row first, left-to-right order.
+ * The grid config can be used for quality control, or optimizations.
+ *
+ * If this param is not set, the component shall assume that grid option is disabled.
+ *
+ *  nSize                      : Size of the structure in bytes
+ *  nVersion                   : OMX specification version information
+ *  nPortIndex                 : Port that this structure applies to (output port for encoders)
+ *  bEnabled                   : Whether grid is enabled. If true, nGrid* specifies the grid
+ *                               config; otherwise nGrid* shall be ignored.
+ *  nGridWidth                 : Width of each tile.
+ *  nGridHeight                : Height of each tile.
+ *  nGridRows                  : Number of rows in the grid.
+ *  nGridCols                  : Number of cols in the grid.
+ */
+typedef struct OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnabled;
+    OMX_U32 nGridWidth;
+    OMX_U32 nGridHeight;
+    OMX_U32 nGridRows;
+    OMX_U32 nGridCols;
+} OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 0c0fedc..eeeba2e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -104,6 +104,7 @@
         "Layer.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
+        "LayerStats.cpp",
         "LayerVector.cpp",
         "MessageQueue.cpp",
         "MonitoredProducer.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b804af8..ec47551 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -98,15 +98,13 @@
 }
 
 bool BufferLayer::isProtected() const {
-    const sp<GraphicBuffer>& buffer(getBE().compositionInfo.mBuffer);
-    return (buffer != 0) &&
-            (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    const sp<GraphicBuffer>& buffer(mActiveBuffer);
+    return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
 bool BufferLayer::isVisible() const {
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
-            (getBE().compositionInfo.mBuffer != nullptr ||
-             getBE().compositionInfo.hwc.sidebandStream != nullptr);
+            (mActiveBuffer != nullptr || getBE().compositionInfo.hwc.sidebandStream != nullptr);
 }
 
 bool BufferLayer::isFixedSize() const {
@@ -162,7 +160,7 @@
                          bool useIdentityTransform) const {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(getBE().compositionInfo.mBuffer == 0)) {
+    if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -240,8 +238,7 @@
         }
 
         // Set things up for texturing.
-        mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(),
-                               getBE().compositionInfo.mBuffer->getHeight());
+        mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
         mTexture.setFiltering(useFiltering);
         mTexture.setMatrix(textureMatrix);
 
@@ -291,12 +288,10 @@
 bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
     if (mBufferLatched) {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPreComposition(mCurrentFrameNumber,
-                                             refreshStartTime);
+        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
     }
     mRefreshPending = false;
-    return mQueuedFrames > 0 || mSidebandStreamChanged ||
-            mAutoRefresh;
+    return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
 }
 bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
                                     const std::shared_ptr<FenceTime>& presentFence,
@@ -308,8 +303,8 @@
     // Update mFrameEventHistory.
     {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence,
-                                              presentFence, compositorTiming);
+        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
+                                              compositorTiming);
     }
 
     // Update mFrameTracker.
@@ -358,8 +353,7 @@
         return;
     }
 
-    auto releaseFenceTime =
-            std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
+    auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
     mReleaseTimeline.updateSignalTimes();
     mReleaseTimeline.push(releaseFenceTime);
 
@@ -412,7 +406,7 @@
     // Capture the old state of the layer for comparisons later
     const State& s(getDrawingState());
     const bool oldOpacity = isOpaque(s);
-    sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer;
+    sp<GraphicBuffer> oldBuffer = mActiveBuffer;
 
     if (!allTransactionsSignaled()) {
         mFlinger->signalLayerUpdate();
@@ -425,12 +419,10 @@
     // buffer mode.
     bool queuedBuffer = false;
     LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName.string(),
-                    mOverrideScalingMode, mFreezeGeometryUpdates);
-    status_t updateResult =
-            mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
-                                                    &mAutoRefresh, &queuedBuffer,
-                                                    mLastFrameNumberReceived);
+                    getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+                    mFreezeGeometryUpdates);
+    status_t updateResult = mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh,
+                                                      &queuedBuffer, mLastFrameNumberReceived);
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
@@ -483,17 +475,16 @@
 
     // Decrement the queued-frames count.  Signal another event if we
     // have more frames pending.
-    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) ||
-        mAutoRefresh) {
+    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
         mFlinger->signalLayerUpdate();
     }
 
     // update the active buffer
-    getBE().compositionInfo.mBuffer =
-            mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
-    // replicated in LayerBE until FE/BE is ready to be synchronized
-    mActiveBuffer = getBE().compositionInfo.mBuffer;
-    if (getBE().compositionInfo.mBuffer == nullptr) {
+    mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
+    getBE().compositionInfo.mBuffer = mActiveBuffer;
+    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+
+    if (mActiveBuffer == nullptr) {
         // this can only happen if the very first buffer was rejected.
         return outDirtyRegion;
     }
@@ -520,8 +511,7 @@
     Rect crop(mConsumer->getCurrentCrop());
     const uint32_t transform(mConsumer->getCurrentTransform());
     const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
-    if ((crop != mCurrentCrop) ||
-        (transform != mCurrentTransform) ||
+    if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
         (scalingMode != mCurrentScalingMode)) {
         mCurrentCrop = crop;
         mCurrentTransform = transform;
@@ -530,15 +520,14 @@
     }
 
     if (oldBuffer != nullptr) {
-        uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
-        uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
-        if (bufWidth != uint32_t(oldBuffer->width) ||
-            bufHeight != uint32_t(oldBuffer->height)) {
+        uint32_t bufWidth = mActiveBuffer->getWidth();
+        uint32_t bufHeight = mActiveBuffer->getHeight();
+        if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) {
             recomputeVisibleRegions = true;
         }
     }
 
-    mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format);
+    mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
     if (oldOpacity != isOpaque(s)) {
         recomputeVisibleRegions = true;
     }
@@ -638,8 +627,8 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
-                                     getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
+    getBE().mHwcLayers[hwcId].bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot,
+                                                       &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
@@ -653,7 +642,7 @@
 bool BufferLayer::isOpaque(const Layer::State& s) const {
     // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) {
+    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
         return false;
     }
 
@@ -668,8 +657,7 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer, true);
     mProducer = new MonitoredProducer(producer, mFlinger, this);
-    mConsumer = new BufferLayerConsumer(consumer,
-            mFlinger->getRenderEngine(), mTextureName, this);
+    mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
     mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mConsumer->setContentsChangedListener(this);
     mConsumer->setName(mName);
@@ -701,8 +689,7 @@
 
         // Ensure that callbacks are handled in order
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                                                               ms2ns(500));
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
                 ALOGE("[%s] Timed out waiting on callback", mName.string());
             }
@@ -725,8 +712,7 @@
 
         // Ensure that callbacks are handled in order
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                                                               ms2ns(500));
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
                 ALOGE("[%s] Timed out waiting on callback", mName.string());
             }
@@ -891,8 +877,7 @@
         // able to be latched. To avoid this, grab this buffer anyway.
         return true;
     }
-    return mQueueItems[0].mFenceTime->getSignalTime() !=
-            Fence::SIGNAL_TIME_PENDING;
+    return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
 }
 
 uint32_t BufferLayer::getEffectiveScalingMode() const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
deleted file mode 100644
index fe7944f..0000000
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright (C) 2010 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_SF_HWCOMPOSER_HWC1_H
-#define ANDROID_SF_HWCOMPOSER_HWC1_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <hardware/hwcomposer_defs.h>
-
-#include <system/graphics.h>
-
-#include <ui/Fence.h>
-
-#include <utils/BitSet.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/StrongPointer.h>
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
-                           const struct timespec *request,
-                           struct timespec *remain);
-
-struct hwc_composer_device_1;
-struct hwc_display_contents_1;
-struct hwc_layer_1;
-struct hwc_procs;
-struct framebuffer_device_t;
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Fence;
-class FloatRect;
-class GraphicBuffer;
-class NativeHandle;
-class Region;
-class String8;
-class SurfaceFlinger;
-
-class HWComposer
-{
-public:
-    class EventHandler {
-        friend class HWComposer;
-        virtual void onVSyncReceived(
-            HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
-        virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected) = 0;
-        virtual void onInvalidateReceived(HWComposer* composer) = 0;
-    protected:
-        virtual ~EventHandler() {}
-    };
-
-    enum {
-        NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
-        MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
-        VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
-    };
-
-    HWComposer(
-            const sp<SurfaceFlinger>& flinger,
-            EventHandler& handler);
-
-    ~HWComposer();
-
-    status_t initCheck() const;
-
-    // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to
-    // be used with createWorkList (and all other methods requiring an ID
-    // below).
-    // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are
-    // always valid.
-    // Returns -1 if an ID cannot be allocated
-    int32_t allocateDisplayId();
-
-    // Recycles the given virtual display ID and frees the associated worklist.
-    // IDs below NUM_BUILTIN_DISPLAYS are not recycled.
-    status_t freeDisplayId(int32_t id);
-
-
-    // Asks the HAL what it can do
-    status_t prepare();
-
-    // commits the list
-    status_t commit();
-
-    // set power mode
-    status_t setPowerMode(int disp, int mode);
-
-    // set active config
-    status_t setActiveConfig(int disp, int mode);
-
-    // reset state when an external, non-virtual display is disconnected
-    void disconnectDisplay(int disp);
-
-    // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
-    status_t createWorkList(int32_t id, size_t numLayers);
-
-    bool supportsFramebufferTarget() const;
-
-    // does this display have layers handled by HWC
-    bool hasHwcComposition(int32_t id) const;
-
-    // does this display have layers handled by GLES
-    bool hasGlesComposition(int32_t id) const;
-
-    // get the releaseFence file descriptor for a display's framebuffer layer.
-    // the release fence is only valid after commit()
-    sp<Fence> getAndResetReleaseFence(int32_t id);
-
-    // needed forward declarations
-    class LayerListIterator;
-
-    // return the visual id to be used to find a suitable EGLConfig for
-    // *ALL* displays.
-    int getVisualID() const;
-
-    // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
-    int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
-    int fbCompositionComplete();
-    void fbDump(String8& result);
-
-    // Set the output buffer and acquire fence for a virtual display.
-    // Returns INVALID_OPERATION if id is not a virtual display.
-    status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
-            const sp<GraphicBuffer>& buf);
-
-    // Get the retire fence for the last committed frame. This fence will
-    // signal when the h/w composer is completely finished with the frame.
-    // For physical displays, it is no longer being displayed. For virtual
-    // displays, writes to the output buffer are complete.
-    sp<Fence> getLastRetireFence(int32_t id) const;
-
-    status_t setCursorPositionAsync(int32_t id, const Rect &pos);
-
-    /*
-     * Interface to hardware composer's layers functionality.
-     * This abstracts the HAL interface to layers which can evolve in
-     * incompatible ways from one release to another.
-     * The idea is that we could extend this interface as we add
-     * features to h/w composer.
-     */
-    class HWCLayerInterface {
-    protected:
-        virtual ~HWCLayerInterface() { }
-    public:
-        virtual int32_t getCompositionType() const = 0;
-        virtual uint32_t getHints() const = 0;
-        virtual sp<Fence> getAndResetReleaseFence() = 0;
-        virtual void setDefaultState() = 0;
-        virtual void setSkip(bool skip) = 0;
-        virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
-        virtual void setBlending(uint32_t blending) = 0;
-        virtual void setTransform(uint32_t transform) = 0;
-        virtual void setFrame(const Rect& frame) = 0;
-        virtual void setCrop(const FloatRect& crop) = 0;
-        virtual void setVisibleRegionScreen(const Region& reg) = 0;
-        virtual void setSurfaceDamage(const Region& reg) = 0;
-        virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
-        virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
-        virtual void setAcquireFenceFd(int fenceFd) = 0;
-        virtual void setPlaneAlpha(uint8_t alpha) = 0;
-        virtual void onDisplayed() = 0;
-    };
-
-    /*
-     * Interface used to implement an iterator to a list
-     * of HWCLayer.
-     */
-    class HWCLayer : public HWCLayerInterface {
-        friend class LayerListIterator;
-        // select the layer at the given index
-        virtual status_t setLayer(size_t index) = 0;
-        virtual HWCLayer* dup() = 0;
-        static HWCLayer* copy(HWCLayer *rhs) {
-            return rhs ? rhs->dup() : nullptr;
-        }
-    protected:
-        virtual ~HWCLayer() { }
-    };
-
-    /*
-     * Iterator through a HWCLayer list.
-     * This behaves more or less like a forward iterator.
-     */
-    class LayerListIterator {
-        friend class HWComposer;
-        HWCLayer* const mLayerList;
-        size_t mIndex;
-
-        LayerListIterator() : mLayerList(nullptr), mIndex(0) { }
-
-        LayerListIterator(HWCLayer* layer, size_t index)
-            : mLayerList(layer), mIndex(index) { }
-
-        // we don't allow assignment, because we don't need it for now
-        LayerListIterator& operator = (const LayerListIterator& rhs);
-
-    public:
-        // copy operators
-        LayerListIterator(const LayerListIterator& rhs)
-            : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
-        }
-
-        ~LayerListIterator() { delete mLayerList; }
-
-        // pre-increment
-        LayerListIterator& operator++() {
-            mLayerList->setLayer(++mIndex);
-            return *this;
-        }
-
-        // dereference
-        HWCLayerInterface& operator * () { return *mLayerList; }
-        HWCLayerInterface* operator -> () { return mLayerList; }
-
-        // comparison
-        bool operator == (const LayerListIterator& rhs) const {
-            return mIndex == rhs.mIndex;
-        }
-        bool operator != (const LayerListIterator& rhs) const {
-            return !operator==(rhs);
-        }
-    };
-
-    // Returns an iterator to the beginning of the layer list
-    LayerListIterator begin(int32_t id);
-
-    // Returns an iterator to the end of the layer list
-    LayerListIterator end(int32_t id);
-
-
-    // Events handling ---------------------------------------------------------
-
-    enum {
-        EVENT_VSYNC = HWC_EVENT_VSYNC
-    };
-
-    void eventControl(int disp, int event, int enabled);
-
-    struct DisplayConfig {
-        uint32_t width;
-        uint32_t height;
-        float xdpi;
-        float ydpi;
-        nsecs_t refresh;
-        android_color_mode_t colorMode;
-        bool operator==(const DisplayConfig& rhs) const {
-            return width == rhs.width &&
-                    height == rhs.height &&
-                    xdpi == rhs.xdpi &&
-                    ydpi == rhs.ydpi &&
-                    refresh == rhs.refresh &&
-                    colorMode == rhs.colorMode;
-        }
-    };
-
-    // Query display parameters.  Pass in a display index (e.g.
-    // HWC_DISPLAY_PRIMARY).
-    nsecs_t getRefreshTimestamp(int disp) const;
-    sp<Fence> getDisplayFence(int disp) const;
-    uint32_t getFormat(int disp) const;
-    bool isConnected(int disp) const;
-
-    // These return the values for the current config of a given display index.
-    // To get the values for all configs, use getConfigs below.
-    uint32_t getWidth(int disp) const;
-    uint32_t getHeight(int disp) const;
-    float getDpiX(int disp) const;
-    float getDpiY(int disp) const;
-    nsecs_t getRefreshPeriod(int disp) const;
-    android_color_mode_t getColorMode(int disp) const;
-
-    const Vector<DisplayConfig>& getConfigs(int disp) const;
-    size_t getCurrentConfig(int disp) const;
-
-    status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
-            uint32_t format);
-
-    // this class is only used to fake the VSync event on systems that don't
-    // have it.
-    class VSyncThread : public Thread {
-        HWComposer& mHwc;
-        mutable Mutex mLock;
-        Condition mCondition;
-        bool mEnabled;
-        mutable nsecs_t mNextFakeVSync;
-        nsecs_t mRefreshPeriod;
-        virtual void onFirstRef();
-        virtual bool threadLoop();
-    public:
-        VSyncThread(HWComposer& hwc);
-        void setEnabled(bool enabled);
-    };
-
-    friend class VSyncThread;
-
-    // for debugging ----------------------------------------------------------
-    void dump(String8& out) const;
-
-private:
-    void loadHwcModule();
-    int loadFbHalModule();
-
-    LayerListIterator getLayerIterator(int32_t id, size_t index);
-
-    struct cb_context;
-
-    static void hook_invalidate(const struct hwc_procs* procs);
-    static void hook_vsync(const struct hwc_procs* procs, int disp,
-            int64_t timestamp);
-    static void hook_hotplug(const struct hwc_procs* procs, int disp,
-            int connected);
-
-    inline void invalidate();
-    inline void vsync(int disp, int64_t timestamp);
-    inline void hotplug(int disp, int connected);
-
-    status_t queryDisplayProperties(int disp);
-
-    status_t setFramebufferTarget(int32_t id,
-            const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
-
-    struct DisplayData {
-        DisplayData();
-        ~DisplayData();
-        Vector<DisplayConfig> configs;
-        size_t currentConfig;
-        uint32_t format;    // pixel format from FB hal, for pre-hwc-1.1
-        bool connected;
-        bool hasFbComp;
-        bool hasOvComp;
-        size_t capacity;
-        hwc_display_contents_1* list;
-        hwc_layer_1* framebufferTarget;
-        buffer_handle_t fbTargetHandle;
-        sp<Fence> lastRetireFence;  // signals when the last set op retires
-        sp<Fence> lastDisplayFence; // signals when the last set op takes
-                                    // effect on screen
-        buffer_handle_t outbufHandle;
-        sp<Fence> outbufAcquireFence;
-
-        // protected by mEventControlLock
-        int32_t events;
-
-        // We need to hold "copies" of these for memory management purposes. The
-        // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
-        // internally doesn't copy the memory unless one of the copies is
-        // modified.
-        Vector<Region> visibleRegions;
-        Vector<Region> surfaceDamageRegions;
-    };
-
-    sp<SurfaceFlinger>              mFlinger;
-    framebuffer_device_t*           mFbDev;
-    struct hwc_composer_device_1*   mHwc;
-    // invariant: mLists[0] != nullptr iff mHwc != nullptr
-    // mLists[i>0] can be nullptr. that display is to be ignored
-    struct hwc_display_contents_1*  mLists[MAX_HWC_DISPLAYS];
-    DisplayData                     mDisplayData[MAX_HWC_DISPLAYS];
-    // protect mDisplayData from races between prepare and dump
-    mutable Mutex mDisplayLock;
-    size_t                          mNumDisplays;
-
-    cb_context*                     mCBContext;
-    EventHandler&                   mEventHandler;
-    size_t                          mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-    sp<VSyncThread>                 mVSyncThread;
-    bool                            mDebugForceFakeVSync;
-    BitSet32                        mAllocatedDisplayIDs;
-
-    // protected by mLock
-    mutable Mutex mLock;
-    mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-
-    // thread-safe
-    mutable Mutex mEventControlLock;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 78dd40b..6104230 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -639,6 +639,7 @@
         hwcInfo.forceClientComposition = true;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
+        hwcInfo.transform = transform;
         auto error = hwcLayer->setTransform(transform);
         ALOGE_IF(error != HWC2::Error::None,
                  "[%s] Failed to set transform %s: "
@@ -1440,7 +1441,7 @@
     info.mMatrix[1][0] = ds.active.transform[1][0];
     info.mMatrix[1][1] = ds.active.transform[1][1];
     {
-        sp<const GraphicBuffer> buffer = getBE().compositionInfo.mBuffer;
+        sp<const GraphicBuffer> buffer = mActiveBuffer;
         if (buffer != 0) {
             info.mActiveBufferWidth = buffer->getWidth();
             info.mActiveBufferHeight = buffer->getHeight();
@@ -1915,6 +1916,21 @@
     layerInfo->set_refresh_pending(isBufferLatched());
 }
 
+void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
+    writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+
+    const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+
+    const Rect& frame = hwcInfo.displayFrame;
+    LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+
+    const FloatRect& crop = hwcInfo.sourceCrop;
+    LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+
+    const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+    layerInfo->set_hwc_transform(transform);
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3671a2b..9c4f1ce 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -42,6 +42,7 @@
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 #include "Transform.h"
+#include "LayerBE.h"
 
 #include <layerproto/LayerProtoHeader.h>
 #include "DisplayHardware/HWComposer.h"
@@ -68,68 +69,6 @@
 
 // ---------------------------------------------------------------------------
 
-struct CompositionInfo {
-    HWC2::Composition compositionType;
-    sp<GraphicBuffer> mBuffer = nullptr;
-    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
-    struct {
-        HWComposer* hwc;
-        sp<Fence> fence;
-        HWC2::BlendMode blendMode;
-        Rect displayFrame;
-        float alpha;
-        FloatRect sourceCrop;
-        HWC2::Transform transform;
-        int z;
-        int type;
-        int appId;
-        Region visibleRegion;
-        Region surfaceDamage;
-        sp<NativeHandle> sidebandStream;
-        android_dataspace dataspace;
-        hwc_color_t color;
-    } hwc;
-    struct {
-        RE::RenderEngine* renderEngine;
-        Mesh* mesh;
-    } renderEngine;
-};
-
-class LayerBE {
-public:
-    LayerBE();
-
-    // The mesh used to draw the layer in GLES composition mode
-    Mesh mMesh;
-
-    // HWC items, accessed from the main thread
-    struct HWCInfo {
-        HWCInfo()
-              : hwc(nullptr),
-                layer(nullptr),
-                forceClientComposition(false),
-                compositionType(HWC2::Composition::Invalid),
-                clearClientTarget(false) {}
-
-        HWComposer* hwc;
-        HWC2::Layer* layer;
-        bool forceClientComposition;
-        HWC2::Composition compositionType;
-        bool clearClientTarget;
-        Rect displayFrame;
-        FloatRect sourceCrop;
-        HWComposerBufferCache bufferCache;
-    };
-
-    // A layer can be attached to multiple displays when operating in mirror mode
-    // (a.k.a: when several displays are attached with equal layerStack). In this
-    // case we need to keep track. In non-mirror mode, a layer will have only one
-    // HWCInfo. This map key is a display layerStack.
-    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
-
-    CompositionInfo compositionInfo;
-};
-
 class Layer : public virtual RefBase {
     static int32_t sSequence;
 
@@ -351,6 +290,8 @@
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
+    void writeToProto(LayerProto* layerInfo, int32_t hwcId);
+
 protected:
     /*
      * onDraw - draws the surface.
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
new file mode 100644
index 0000000..d0cc8e7
--- /dev/null
+++ b/services/surfaceflinger/LayerBE.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/Region.h>
+
+#include "SurfaceFlinger.h"
+
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
+#include "RenderEngine/Mesh.h"
+
+namespace android {
+
+struct CompositionInfo {
+    HWC2::Composition compositionType;
+    sp<GraphicBuffer> mBuffer = nullptr;
+    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    struct {
+        HWC2::Layer* hwcLayer;
+        int32_t hwid = -1;
+        sp<Fence> fence;
+        HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
+        Rect displayFrame;
+        float alpha;
+        FloatRect sourceCrop;
+        HWC2::Transform transform = HWC2::Transform::None;
+        int z;
+        int type;
+        int appId;
+        Region visibleRegion;
+        Region surfaceDamage;
+        sp<NativeHandle> sidebandStream;
+        android_dataspace dataspace;
+        hwc_color_t color;
+    } hwc;
+    struct {
+        Mesh* mesh;
+    } renderEngine;
+};
+
+class LayerBE {
+public:
+    LayerBE();
+
+    // The mesh used to draw the layer in GLES composition mode
+    Mesh mMesh;
+
+    // HWC items, accessed from the main thread
+    struct HWCInfo {
+        HWCInfo()
+              : hwc(nullptr),
+                layer(nullptr),
+                forceClientComposition(false),
+                compositionType(HWC2::Composition::Invalid),
+                clearClientTarget(false),
+                transform(HWC2::Transform::None) {}
+
+        HWComposer* hwc;
+        HWC2::Layer* layer;
+        bool forceClientComposition;
+        HWC2::Composition compositionType;
+        bool clearClientTarget;
+        Rect displayFrame;
+        FloatRect sourceCrop;
+        HWComposerBufferCache bufferCache;
+        HWC2::Transform transform;
+    };
+
+
+    // A layer can be attached to multiple displays when operating in mirror mode
+    // (a.k.a: when several displays are attached with equal layerStack). In this
+    // case we need to keep track. In non-mirror mode, a layer will have only one
+    // HWCInfo. This map key is a display layerStack.
+    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+
+    CompositionInfo compositionInfo;
+};
+
+}; // namespace android
+
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 6a33148..cc39550 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -37,6 +37,13 @@
     rectProto->set_right(rect.right);
 }
 
+void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
+    rectProto->set_left(rect.left);
+    rectProto->set_top(rect.top);
+    rectProto->set_bottom(rect.bottom);
+    rectProto->set_right(rect.right);
+}
+
 void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
     colorProto->set_r(color.r);
     colorProto->set_g(color.g);
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 45a0b5d..860da63 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -29,6 +29,7 @@
 class LayerProtoHelper {
 public:
     static void writeToProto(const Rect& rect, RectProto* rectProto);
+    static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
     static void writeToProto(const Region& region, RegionProto* regionProto);
     static void writeToProto(const half4 color, ColorProto* colorProto);
     static void writeToProto(const Transform& transform, TransformProto* transformProto);
@@ -36,4 +37,4 @@
 };
 
 } // namespace surfaceflinger
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
new file mode 100644
index 0000000..ea2542c
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+#undef LOG_TAG
+#define LOG_TAG "LayerStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LayerStats.h"
+#include "DisplayHardware/HWComposer.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void LayerStats::enable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mEnabled) return;
+    mLayerStatsMap.clear();
+    mEnabled = true;
+    ALOGD("Logging enabled");
+}
+
+void LayerStats::disable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mEnabled) return;
+    mEnabled = false;
+    ALOGD("Logging disabled");
+}
+
+void LayerStats::clear() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    mLayerStatsMap.clear();
+    ALOGD("Cleared current layer stats");
+}
+
+bool LayerStats::isEnabled() {
+    return mEnabled;
+}
+
+void LayerStats::traverseLayerTreeStatsLocked(
+        const std::vector<const LayerProtoParser::Layer*>& layerTree,
+        const LayerProtoParser::LayerGlobal* layerGlobal) {
+    for (auto layer : layerTree) {
+        if (!layer) continue;
+        traverseLayerTreeStatsLocked(layer->children, layerGlobal);
+        std::string key =
+                base::StringPrintf("%s,%s,%s,%s,%s,%s,%s,%s,%s",
+                                   destinationLocation(layer->hwcFrame.left,
+                                                       layerGlobal->resolution[0], true),
+                                   destinationLocation(layer->hwcFrame.top,
+                                                       layerGlobal->resolution[1], false),
+                                   destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+                                                   layerGlobal->resolution[0], true),
+                                   destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                                                   layerGlobal->resolution[1], false),
+                                   layer->type.c_str(), scaleRatioWH(layer).c_str(),
+                                   layerTransform(layer->hwcTransform), layer->pixelFormat.c_str(),
+                                   layer->dataspace.c_str());
+        mLayerStatsMap[key]++;
+    }
+}
+
+void LayerStats::logLayerStats(const LayersProto& layersProto) {
+    ATRACE_CALL();
+    auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
+    auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+    std::lock_guard<std::mutex> lock(mMutex);
+    traverseLayerTreeStatsLocked(layerTree, &layerGlobal);
+    LayerProtoParser::destroyLayerTree(layerTree);
+}
+
+void LayerStats::dump(String8& result) {
+    ATRACE_CALL();
+    ALOGD("Dumping");
+    result.append("Count,DstPosX,DstPosY,DstWidth,DstHeight,LayerType,WScale,HScale,");
+    result.append("Transform,PixelFormat,Dataspace\n");
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto& u : mLayerStatsMap) {
+        result.appendFormat("%u,%s\n", u.second, u.first.c_str());
+    }
+}
+
+const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
+    static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
+    int32_t ratio = location * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isHorizontal) {
+        // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
+        if (ratio > 6) return "3/4";
+        // use index 0, 2, 4, 6
+        return locationArray[ratio & ~1];
+    }
+    if (ratio > 7) return "7/8";
+    return locationArray[ratio];
+}
+
+const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
+    static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
+    int32_t ratio = size * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isWidth) {
+        // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
+        if (ratio > 6) return "1";
+        // use index 1, 3, 5, 7
+        return sizeArray[ratio | 1];
+    }
+    if (ratio > 7) return "1";
+    return sizeArray[ratio];
+}
+
+const char* LayerStats::layerTransform(int32_t transform) {
+    return getTransformName(static_cast<hwc_transform_t>(transform));
+}
+
+std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
+    if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
+    std::string ret = "";
+    if (isRotated(layer->hwcTransform)) {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+    } else {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+    }
+    return ret;
+}
+
+const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
+    // Make scale buckets from <1/64 to >= 16, to avoid floating point
+    // calculation, x64 on destinationScale first
+    int32_t scale = destinationScale * 64 / sourceScale;
+    if (!scale) return "<1/64";
+    if (scale < 2) return "1/64";
+    if (scale < 4) return "1/32";
+    if (scale < 8) return "1/16";
+    if (scale < 16) return "1/8";
+    if (scale < 32) return "1/4";
+    if (scale < 64) return "1/2";
+    if (scale < 128) return "1";
+    if (scale < 256) return "2";
+    if (scale < 512) return "4";
+    if (scale < 1024) return "8";
+    return ">=16";
+}
+
+bool LayerStats::isRotated(int32_t transform) {
+    return transform & HWC_TRANSFORM_ROT_90;
+}
+
+bool LayerStats::isVFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_V;
+}
+
+bool LayerStats::isHFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_H;
+}
+
+}  // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
new file mode 100644
index 0000000..1924110
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.h
@@ -0,0 +1,68 @@
+/*
+ * 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 <layerproto/LayerProtoHeader.h>
+#include <layerproto/LayerProtoParser.h>
+#include <mutex>
+#include <unordered_map>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+class String8;
+
+class LayerStats {
+public:
+    void enable();
+    void disable();
+    void clear();
+    bool isEnabled();
+    void logLayerStats(const LayersProto& layersProto);
+    void dump(String8& result);
+
+private:
+    // Traverse layer tree to get all visible layers' stats
+    void traverseLayerTreeStatsLocked(const std::vector<const LayerProtoParser::Layer*>& layerTree,
+                                      const LayerProtoParser::LayerGlobal* layerGlobal);
+    // Convert layer's top-left position into 8x8 percentage of the display
+    static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
+    // Convert layer's size into 8x8 percentage of the display
+    static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
+    // Return the name of the transform
+    static const char* layerTransform(int32_t transform);
+    // Calculate scale ratios of layer's width/height with rotation information
+    static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
+    // Calculate scale ratio from source to destination and convert to string
+    static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
+    // Return whether the original buffer is rotated in final composition
+    static bool isRotated(int32_t transform);
+    // Return whether the original buffer is V-flipped in final composition
+    static bool isVFlipped(int32_t transform);
+    // Return whether the original buffer is H-flipped in final composition
+    static bool isHFlipped(int32_t transform);
+
+    bool mEnabled = false;
+    // Protect mLayersStatsMap
+    std::mutex mMutex;
+    // Hashmap for tracking the layer stats
+    // KEY is a concatenation of a particular set of layer properties
+    // VALUE is the number of times this particular get scanned out
+    std::unordered_map<std::string, uint32_t> mLayerStatsMap;
+};
+
+}  // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cb410a1..29c1ee2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1449,6 +1449,7 @@
     setUpHWComposer();
     doDebugFlashRegions();
     doTracing("handleRefresh");
+    logLayerStats();
     doComposition();
     postComposition(refreshStartTime);
 
@@ -1518,6 +1519,25 @@
     }
 }
 
+void SurfaceFlinger::logLayerStats() {
+    ATRACE_CALL();
+    if (CC_UNLIKELY(mLayerStats.isEnabled())) {
+        int32_t hwcId = -1;
+        for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
+            const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
+            if (displayDevice->isPrimary()) {
+                hwcId = displayDevice->getHwcDisplayId();
+                break;
+            }
+        }
+        if (hwcId < 0) {
+            ALOGE("LayerStats: Hmmm, no primary display?");
+            return;
+        }
+        mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+    }
+}
+
 void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
@@ -3695,6 +3715,34 @@
                 dumpWideColorInfo(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--enable-layer-stats"))) {
+                index++;
+                mLayerStats.enable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--disable-layer-stats"))) {
+                index++;
+                mLayerStats.disable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--clear-layer-stats"))) {
+                index++;
+                mLayerStats.clear();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--dump-layer-stats"))) {
+                index++;
+                mLayerStats.dump(result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
@@ -3902,6 +3950,25 @@
     return layersProto;
 }
 
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+    LayersProto layersProto;
+
+    const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
+    SizeProto* resolution = layersProto.mutable_resolution();
+    resolution->set_w(displayDevice->getWidth());
+    resolution->set_h(displayDevice->getHeight());
+
+    mDrawingState.traverseInZOrder([&](Layer* layer) {
+        if (!layer->visibleRegion.isEmpty() &&
+            layer->getBE().mHwcLayers.count(hwcId)) {
+            LayerProto* layerProto = layersProto.add_layers();
+            layer->writeToProto(layerProto, hwcId);
+        }
+    });
+
+    return layersProto;
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 392acaa..d6aa142 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -44,6 +44,7 @@
 #include <gui/LayerState.h>
 
 #include <gui/OccupancyTracker.h>
+#include <gui/BufferQueue.h>
 
 #include <hardware/hwcomposer_defs.h>
 
@@ -55,11 +56,13 @@
 #include "DisplayDevice.h"
 #include "DispSync.h"
 #include "FrameTracker.h"
+#include "LayerStats.h"
 #include "LayerVector.h"
 #include "MessageQueue.h"
 #include "SurfaceInterceptor.h"
 #include "SurfaceTracing.h"
 #include "StartPropertySetThread.h"
+#include "LayerBE.h"
 
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/HWComposer.h"
@@ -629,6 +632,7 @@
     void doComposition();
     void doDebugFlashRegions();
     void doTracing(const char* where);
+    void logLayerStats();
     void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
 
     // compose surfaces for display hw. this fails if using GL and the surface
@@ -691,6 +695,7 @@
     void dumpBufferingStats(String8& result) const;
     void dumpWideColorInfo(String8& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+    LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -775,6 +780,7 @@
     bool mPropagateBackpressure = true;
     SurfaceInterceptor mInterceptor;
     SurfaceTracing mTracing;
+    LayerStats mLayerStats;
     bool mUseHwcVirtualDisplays = false;
 
     // Restrict layers to use two buffers in their bufferqueues.
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index bf37e1e..7483abd 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -38,6 +38,19 @@
     return lhs->id < rhs->id;
 }
 
+const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
+        const LayersProto& layersProto) {
+    return {{layersProto.resolution().w(), layersProto.resolution().h()}};
+}
+
+void LayerProtoParser::destroyLayerTree(
+        const std::vector<const LayerProtoParser::Layer*>& layerTree) {
+    for (auto layer : layerTree) {
+        destroyLayerTree(layer->children);
+        delete layer;
+    }
+}
+
 std::vector<const LayerProtoParser::Layer*> LayerProtoParser::generateLayerTree(
         const LayersProto& layersProto) {
     auto layerMap = generateMap(layersProto);
@@ -102,6 +115,9 @@
     layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
     layer->queuedFrames = layerProto.queued_frames();
     layer->refreshPending = layerProto.refresh_pending();
+    layer->hwcFrame = generateRect(layerProto.hwc_frame());
+    layer->hwcCrop = generateFloatRect(layerProto.hwc_crop());
+    layer->hwcTransform = layerProto.hwc_transform();
 
     return layer;
 }
@@ -127,6 +143,16 @@
     return rect;
 }
 
+LayerProtoParser::FloatRect LayerProtoParser::generateFloatRect(const FloatRectProto& rectProto) {
+    LayerProtoParser::FloatRect rect;
+    rect.left = rectProto.left();
+    rect.top = rectProto.top();
+    rect.right = rectProto.right();
+    rect.bottom = rectProto.bottom();
+
+    return rect;
+}
+
 LayerProtoParser::Transform LayerProtoParser::generateTransform(
         const TransformProto& transformProto) {
     LayerProtoParser::Transform transform;
@@ -242,6 +268,10 @@
     return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
 }
 
+std::string LayerProtoParser::FloatRect::to_string() const {
+    return StringPrintf("[%.2f, %.2f, %.2f, %.2f]", left, top, right, bottom);
+}
+
 std::string LayerProtoParser::Region::to_string(const char* what) const {
     std::string result =
             StringPrintf("  Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id),
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 78c6cd1..4747275 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <layerproto/LayerProtoHeader.h>
 
@@ -56,6 +57,16 @@
         std::string to_string() const;
     };
 
+    class FloatRect {
+    public:
+        float left;
+        float top;
+        float right;
+        float bottom;
+
+        std::string to_string() const;
+    };
+
     class Region {
     public:
         uint64_t id;
@@ -95,11 +106,21 @@
         LayerProtoParser::ActiveBuffer activeBuffer;
         int32_t queuedFrames;
         bool refreshPending;
+        LayerProtoParser::Rect hwcFrame;
+        LayerProtoParser::FloatRect hwcCrop;
+        int32_t hwcTransform;
 
         std::string to_string() const;
     };
 
+    class LayerGlobal {
+    public:
+        int2 resolution;
+    };
+
+    static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
     static std::vector<const Layer*> generateLayerTree(const LayersProto& layersProto);
+    static void destroyLayerTree(const std::vector<const LayerProtoParser::Layer*>& layerTree);
     static std::string layersToString(const std::vector<const LayerProtoParser::Layer*> layers);
 
 private:
@@ -107,6 +128,7 @@
     static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto);
     static LayerProtoParser::Region generateRegion(const RegionProto& regionProto);
     static LayerProtoParser::Rect generateRect(const RectProto& rectProto);
+    static LayerProtoParser::FloatRect generateFloatRect(const FloatRectProto& rectProto);
     static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto);
     static LayerProtoParser::ActiveBuffer generateActiveBuffer(
             const ActiveBufferProto& activeBufferProto);
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index d27dc9b..e232f05 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,6 +7,7 @@
 // Contains a list of all layers.
 message LayersProto {
   repeated LayerProto layers = 1;
+  optional SizeProto resolution = 2;
 }
 
 // Information about each layer.
@@ -64,6 +65,12 @@
   // The number of frames available.
   optional int32 queued_frames = 28;
   optional bool refresh_pending = 29;
+  // The layer's composer backend destination frame
+  optional RectProto hwc_frame = 30;
+  // The layer's composer backend source crop
+  optional FloatRectProto hwc_crop = 31;
+  // The layer's composer backend transform
+  optional int32 hwc_transform = 32;
 }
 
 message PositionProto {
@@ -95,6 +102,13 @@
   optional int32 bottom = 4;
 }
 
+message FloatRectProto {
+  optional float left = 1;
+  optional float top = 2;
+  optional float right = 3;
+  optional float bottom = 4;
+}
+
 message ActiveBufferProto {
   optional uint32 width = 1;
   optional uint32 height = 2;
@@ -107,4 +121,4 @@
   optional float g = 2;
   optional float b = 3;
   optional float a = 4;
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index fafc54e..21590df 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -165,9 +165,7 @@
 
     EXPECT_CALL(*mComposer, getActiveConfig(DisplayDevice::DISPLAY_PRIMARY, _))
             .WillOnce(DoAll(SetArgPointee<1>(0), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer, getColorModes(DisplayDevice::DISPLAY_PRIMARY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::NATIVE})),
-                            Return(Error::NONE)));
+    EXPECT_CALL(*mComposer, getColorModes(DisplayDevice::DISPLAY_PRIMARY, _)).Times(0);
     EXPECT_CALL(*mComposer, getHdrCapabilities(DisplayDevice::DISPLAY_PRIMARY, _, _, _, _))
             .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));