C++程序  |  899行  |  25.74 KB

/*
// Copyright (c) 2014 Intel Corporation 
//
// 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 <HwcTrace.h>
#include <IDisplayDevice.h>
#include <DisplayQuery.h>
#include <BufferManager.h>
#include <DisplayPlaneManager.h>
#include <Hwcomposer.h>
#include <DisplayAnalyzer.h>
#include <cutils/properties.h>
#include <GraphicBuffer.h>
#include <ExternalDevice.h>
#include <VirtualDevice.h>

namespace android {
namespace intel {

DisplayAnalyzer::DisplayAnalyzer()
    : mInitialized(false),
      mVideoExtModeEnabled(true),
      mVideoExtModeEligible(false),
      mVideoExtModeActive(false),
      mBlankDevice(false),
      mOverlayAllowed(true),
      mActiveInputState(true),
      mIgnoreVideoSkipFlag(false),
      mProtectedVideoSession(false),
      mCachedNumDisplays(0),
      mCachedDisplays(0),
      mPendingEvents(),
      mEventMutex(),
      mEventHandledCondition()
{
}

DisplayAnalyzer::~DisplayAnalyzer()
{
}

bool DisplayAnalyzer::initialize()
{
    // by default video extended mode is enabled
    char prop[PROPERTY_VALUE_MAX];
    if (property_get("hwc.video.extmode.enable", prop, "1") > 0) {
        mVideoExtModeEnabled = atoi(prop) ? true : false;
    }
    mVideoExtModeEligible = false;
    mVideoExtModeActive = false;
    mBlankDevice = false;
    mOverlayAllowed = true;
    mActiveInputState = true;
    mIgnoreVideoSkipFlag = false;
    mProtectedVideoSession = false;
    mCachedNumDisplays = 0;
    mCachedDisplays = 0;
    mPendingEvents.clear();
    mVideoStateMap.clear();
    mInitialized = true;

    return true;
}

void DisplayAnalyzer::deinitialize()
{
    mPendingEvents.clear();
    mVideoStateMap.clear();
    mInitialized = false;
}

void DisplayAnalyzer::analyzeContents(
        size_t numDisplays, hwc_display_contents_1_t** displays)
{
    // cache and use them only in this context during analysis
    mCachedNumDisplays = numDisplays;
    mCachedDisplays = displays;

    handlePendingEvents();

    if (mVideoExtModeEnabled) {
        handleVideoExtMode();
    }

    if (mBlankDevice) {
        // this will make sure device is blanked after geometry changes.
        // blank event is only processed once
        blankSecondaryDevice();
    }
}

void DisplayAnalyzer::handleVideoExtMode()
{
    bool eligible = mVideoExtModeEligible;
    checkVideoExtMode();
    if (eligible == mVideoExtModeEligible) {
        if (mVideoExtModeActive) {
            // need to mark all layers
            setCompositionType(0, HWC_OVERLAY, false);
        }
        return;
    }

    if (mVideoExtModeEligible) {
        if (mActiveInputState) {
            VTRACE("input is active");
        } else {
            enterVideoExtMode();
        }
    } else {
        exitVideoExtMode();
    }
}

void DisplayAnalyzer::checkVideoExtMode()
{
    if (mVideoStateMap.size() != 1) {
        mVideoExtModeEligible = false;
        return;
    }

    Hwcomposer *hwc = &Hwcomposer::getInstance();

    ExternalDevice *eDev = static_cast<ExternalDevice *>(hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL));
    VirtualDevice  *vDev = static_cast<VirtualDevice  *>(hwc->getDisplayDevice(IDisplayDevice::DEVICE_VIRTUAL));

    if ((!eDev || !eDev->isConnected()) && (!vDev || !vDev->isFrameServerActive())) {
        mVideoExtModeEligible = false;
        return;
    }

    bool geometryChanged = false;
    int activeDisplays = 0;

    hwc_display_contents_1_t *content = NULL;
    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
        content = mCachedDisplays[i];
        if (content == NULL) {
            continue;
        }
        activeDisplays++;
        if (content->flags & HWC_GEOMETRY_CHANGED) {
            geometryChanged = true;
        }
    }

    if (activeDisplays <= 1) {
        mVideoExtModeEligible = false;
        return;
    }

    // video state update event may come later than geometry change event.
    // in that case, video extended mode is not detected properly.
#if 0
    if (geometryChanged == false) {
        // use previous analysis result
        return;
    }
#endif
    // reset eligibility of video extended mode
    mVideoExtModeEligible = false;

    // check if there is video layer in the primary device
    content = mCachedDisplays[0];
    if (content == NULL) {
        return;
    }

    buffer_handle_t videoHandle = 0;
    bool videoLayerExist = false;
    bool videoFullScreenOnPrimary = false;
    bool isVideoLayerSkipped = false;

    // exclude the frame buffer target layer
    for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
        videoLayerExist = isVideoLayer(content->hwLayers[j]);
        if (videoLayerExist) {
            if ((content->hwLayers[j].flags & HWC_SKIP_LAYER)) {
                isVideoLayerSkipped = true;
            }
            videoHandle = content->hwLayers[j].handle;
            videoFullScreenOnPrimary = isVideoFullScreen(0, content->hwLayers[j]);
            break;
        }
    }

    if (videoLayerExist == false) {
        // no video layer is found in the primary layer
        return;
    }

    // check whether video layer exists in external device or virtual device
    // TODO: video may exist in virtual device but no in external device or vice versa
    // TODO: multiple video layers are not addressed here
    for (int i = 1; i < (int)mCachedNumDisplays; i++) {
        content = mCachedDisplays[i];
        if (content == NULL) {
            continue;
        }

        // exclude the frame buffer target layer
        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
            if (content->hwLayers[j].handle == videoHandle) {
                isVideoLayerSkipped |= (content->hwLayers[j].flags & HWC_SKIP_LAYER);
                VTRACE("video layer exists in device %d", i);
                if (isVideoLayerSkipped || videoFullScreenOnPrimary){
                    VTRACE("Video ext mode eligible, %d, %d",
                            isVideoLayerSkipped, videoFullScreenOnPrimary);
                    mVideoExtModeEligible = true;
                } else {
                    mVideoExtModeEligible = isVideoFullScreen(i, content->hwLayers[j]);
                }
                return;
            }
        }
    }
}

bool DisplayAnalyzer::isVideoExtModeActive()
{
    return mVideoExtModeActive;
}

bool DisplayAnalyzer::isVideoExtModeEnabled()
{
#if 1
    // enable it for run-time debugging purpose.
    char prop[PROPERTY_VALUE_MAX];
    if (property_get("hwc.video.extmode.enable", prop, "1") > 0) {
        mVideoExtModeEnabled = atoi(prop) ? true : false;
    }
    ITRACE("video extended mode enabled: %d", mVideoExtModeEnabled);
#endif

    return mVideoExtModeEnabled;
}

bool DisplayAnalyzer::isVideoLayer(hwc_layer_1_t &layer)
{
    bool ret = false;
    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
    if (!layer.handle) {
        return false;
    }
    DataBuffer *buffer = bm->lockDataBuffer(layer.handle);
     if (!buffer) {
         ETRACE("failed to get buffer");
     } else {
        ret = DisplayQuery::isVideoFormat(buffer->getFormat());
        bm->unlockDataBuffer(buffer);
    }
    return ret;
}

bool DisplayAnalyzer::isVideoFullScreen(int device, hwc_layer_1_t &layer)
{
    IDisplayDevice *displayDevice = Hwcomposer::getInstance().getDisplayDevice(device);
    if (!displayDevice) {
        return false;
    }
    int width = 0, height = 0;
    if (!displayDevice->getDisplaySize(&width, &height)) {
        return false;
    }

    VTRACE("video left %d, right %d, top %d, bottom %d, device width %d, height %d",
        layer.displayFrame.left, layer.displayFrame.right,
        layer.displayFrame.top, layer.displayFrame.bottom,
        width, height);

    // full-screen defintion:
    // width of target display frame == width of target device, with 1 pixel of tolerance, or
    // Height of target display frame == height of target device, with 1 pixel of tolerance, or
    // width * height of display frame > 90% of width * height of display device, or
    // any of above condition is met on either primary display or secondary display
    int dstW = layer.displayFrame.right - layer.displayFrame.left;
    int dstH = layer.displayFrame.bottom - layer.displayFrame.top;

    if (abs(dstW - width) > 1 &&
        abs(dstH - height) > 1 &&
        dstW * dstH * 10 < width * height * 9) {
        VTRACE("video is not full-screen");
        return false;
    }
    return true;
}

bool DisplayAnalyzer::isOverlayAllowed()
{
    return mOverlayAllowed;
}

int DisplayAnalyzer::getVideoInstances()
{
    return (int)mVideoStateMap.size();
}

void DisplayAnalyzer::postHotplugEvent(bool connected)
{
    if (!connected) {
        // enable vsync on the primary device immediately
        Hwcomposer::getInstance().getVsyncManager()->enableDynamicVsync(true);
    }

    // handle hotplug event (vsync switch) asynchronously
    Event e;
    e.type = HOTPLUG_EVENT;
    e.bValue = connected;
    postEvent(e);
    Hwcomposer::getInstance().invalidate();
}

void DisplayAnalyzer::postVideoEvent(int instanceID, int state)
{
    Event e;
    e.type = VIDEO_EVENT;
    e.videoEvent.instanceID = instanceID;
    e.videoEvent.state = state;
    postEvent(e);
    if ((state == VIDEO_PLAYBACK_STARTING) ||
        (state == VIDEO_PLAYBACK_STOPPING && mProtectedVideoSession)) {
        Hwcomposer::getInstance().invalidate();
        mOverlayAllowed = false;
        hwc_display_contents_1_t *content = NULL;
        for (int i = 0; i < (int)mCachedNumDisplays; i++) {
            setCompositionType(i, HWC_FRAMEBUFFER, true);
        }
        // wait for up to 100ms until overlay is disabled.
        int loop = 0;
        while (loop++ < 6) {
            if (Hwcomposer::getInstance().getPlaneManager()->isOverlayPlanesDisabled())
                break;
            usleep(16700);
        }
        if (loop >= 6) {
            WTRACE("timeout disabling overlay ");
        }
    }
}

void DisplayAnalyzer::postBlankEvent(bool blank)
{
    Event e;
    e.type = BLANK_EVENT;
    e.bValue = blank;
    postEvent(e);
    Hwcomposer::getInstance().invalidate();
}

void DisplayAnalyzer::postInputEvent(bool active)
{
    Event e;
    e.type = INPUT_EVENT;
    e.bValue = active;
    postEvent(e);
    Hwcomposer::getInstance().invalidate();
}

void DisplayAnalyzer::postIdleEntryEvent(void)
{
    Event e;
    e.type = IDLE_ENTRY_EVENT;
    e.nValue = 0;
    postEvent(e);
}

void DisplayAnalyzer::postEvent(Event& e)
{
    Mutex::Autolock lock(mEventMutex);
    mPendingEvents.add(e);
}

bool DisplayAnalyzer::getEvent(Event& e)
{
    Mutex::Autolock lock(mEventMutex);
    if (mPendingEvents.size() == 0) {
        return false;
    }
    e = mPendingEvents[0];
    mPendingEvents.removeAt(0);
    return true;
}

void DisplayAnalyzer::handlePendingEvents()
{
    // handle one event per analysis to avoid blocking surface flinger
    // some event may take lengthy time to process
    Event e;
    if (!getEvent(e)) {
        return;
    }

    switch (e.type) {
    case HOTPLUG_EVENT:
        handleHotplugEvent(e.bValue);
        break;
    case BLANK_EVENT:
        handleBlankEvent(e.bValue);
        break;
    case VIDEO_EVENT:
        handleVideoEvent(e.videoEvent.instanceID, e.videoEvent.state);
        break;
    case TIMING_EVENT:
        handleTimingEvent();
        break;
    case INPUT_EVENT:
        handleInputEvent(e.bValue);
        break;
    case DPMS_EVENT:
        handleDpmsEvent(e.nValue);
        break;
    case IDLE_ENTRY_EVENT:
        handleIdleEntryEvent(e.nValue);
        break;
    case IDLE_EXIT_EVENT:
        handleIdleExitEvent();
        break;
    case VIDEO_CHECK_EVENT:
        handleVideoCheckEvent();
        break;
    }
}

void DisplayAnalyzer::handleHotplugEvent(bool connected)
{
    Hwcomposer *hwc = &Hwcomposer::getInstance();
    if (connected) {
        if (mVideoStateMap.size() == 1) {
            // Some video apps wouldn't update video state again when plugin HDMI
            // and fail to reset refresh rate
            ExternalDevice *dev = NULL;
            dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
            if (!dev || !dev->isConnected()) {
                ITRACE("External device isn't connected");
                return;
            }
            if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) {
                VTRACE("Timing of external device is fixed.");
                return;
            }
            VideoSourceInfo info;
            int instanceID = mVideoStateMap.keyAt(0);
            status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo(
                    instanceID, &info);
            if (err == NO_ERROR) {
                int hz = dev->getRefreshRate();
                if (hz > 0 && info.frameRate > 0 && hz != info.frameRate) {
                    ITRACE("Old Hz %d, new one %d", hz, info.frameRate);
                    dev->setRefreshRate(info.frameRate);
                } else
                    WTRACE("Old Hz %d is invalid, %d", hz, info.frameRate);
            }
        }
    } else {
        if (mVideoStateMap.size() == 1) {
            // Reset input state if HDMI is plug out to
            // avoid entering extended mode immediately after HDMI is plug in
            mActiveInputState = true;
        }
    }
}

void DisplayAnalyzer::handleBlankEvent(bool blank)
{
    mBlankDevice = blank;
    // force geometry changed in the secondary device to reset layer composition type
    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
        if (i == IDisplayDevice::DEVICE_PRIMARY) {
            continue;
        }
        if (mCachedDisplays[i]) {
            mCachedDisplays[i]->flags |= HWC_GEOMETRY_CHANGED;
        }
    }
    blankSecondaryDevice();
}

void DisplayAnalyzer::handleTimingEvent()
{
    // check whether external device is connected, reset refresh rate to match video frame rate
    // if video is in playing state or reset refresh rate to default preferred one if video is not
    // at playing state
    Hwcomposer *hwc = &Hwcomposer::getInstance();
    ExternalDevice *dev = NULL;
    dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
    if (!dev) {
        return;
    }

    if (!dev->isConnected()) {
        return;
    }

    if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) {
        VTRACE("Timing of external device is fixed.");
        return;
    }

    int hz = 0;
    if (mVideoStateMap.size() == 1) {
        VideoSourceInfo info;
        int instanceID = mVideoStateMap.keyAt(0);
        status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo(
                instanceID, &info);
        if (err == NO_ERROR) {
            hz = info.frameRate;
        }
    }

    dev->setRefreshRate(hz);
}

void DisplayAnalyzer::handleVideoEvent(int instanceID, int state)
{
    mVideoStateMap.removeItem(instanceID);
    if (state != VIDEO_PLAYBACK_STOPPED) {
        mVideoStateMap.add(instanceID, state);
    }

    Hwcomposer *hwc = &Hwcomposer::getInstance();

    // sanity check
    if (hwc->getMultiDisplayObserver()->getVideoSessionNumber() !=
        (int)mVideoStateMap.size()) {
        WTRACE("session number does not match!!");
        mVideoStateMap.clear();
        if (state != VIDEO_PLAYBACK_STOPPED) {
            mVideoStateMap.add(instanceID, state);
        }
    }

    // check if composition type needs to be reset
    bool reset = false;
    if ((state == VIDEO_PLAYBACK_STARTING) ||
        (state == VIDEO_PLAYBACK_STOPPING && mProtectedVideoSession)) {
        // if video is in starting or stopping stage, overlay use is temporarily not allowed to
        // avoid scrambed RGB overlay if video is protected.
        mOverlayAllowed = false;
        reset = true;
    } else {
        reset = !mOverlayAllowed;
        mOverlayAllowed = true;
    }

    if (reset) {
        hwc_display_contents_1_t *content = NULL;
        for (int i = 0; i < (int)mCachedNumDisplays; i++) {
            setCompositionType(i, HWC_FRAMEBUFFER, true);
        }
    }

    if (mVideoStateMap.size() == 0) {
        // reset active input state after video playback stops.
        // MDS should update input state in 5 seconds after video playback starts
        mActiveInputState = true;
    }

    mProtectedVideoSession = false;
    if (state == VIDEO_PLAYBACK_STARTED) {
        VideoSourceInfo info;
        hwc->getMultiDisplayObserver()->getVideoSourceInfo(
                getFirstVideoInstanceSessionID(), &info);
        mProtectedVideoSession = info.isProtected;
    }
    // Setting timing immediately,
    // Don't posthone to next circle
    handleTimingEvent();

    handleVideoCheckEvent();
}

void DisplayAnalyzer::blankSecondaryDevice()
{
    hwc_display_contents_1_t *content = NULL;
    hwc_layer_1 *layer = NULL;
    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
        if (i == IDisplayDevice::DEVICE_PRIMARY) {
            continue;
        }
        content = mCachedDisplays[i];
        if (content == NULL) {
            continue;
        }

        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
            layer = &content->hwLayers[j];
            if (!layer) {
                continue;
            }
            if (mBlankDevice) {
                layer->hints |= HWC_HINT_CLEAR_FB;
                layer->flags &= ~HWC_SKIP_LAYER;
                layer->compositionType = HWC_OVERLAY;
            } else {
                layer->hints &= ~HWC_HINT_CLEAR_FB;
                layer->compositionType = HWC_FRAMEBUFFER;
            }
        }
    }
}

void DisplayAnalyzer::handleInputEvent(bool active)
{
    if (active == mActiveInputState) {
        WTRACE("same input state: %d", active);
    }
    mActiveInputState = active;
    if (!mVideoExtModeEligible) {
        ITRACE("not eligible for video extended mode");
        return;
    }

    if (active) {
        exitVideoExtMode();
    } else {
        enterVideoExtMode();
    }
}

void DisplayAnalyzer::handleDpmsEvent(int delayCount)
{
    if (mActiveInputState || !mVideoExtModeEligible) {
        ITRACE("aborting display power off in video extended mode");
        return;
    }

    if (delayCount < DELAY_BEFORE_DPMS_OFF) {
        Event e;
        e.type = DPMS_EVENT;
        e.nValue = delayCount + 1;
        postEvent(e);
        Hwcomposer::getInstance().invalidate();
        return;
    }

    if (Hwcomposer::getInstance().getVsyncManager()->getVsyncSource() ==
        IDisplayDevice::DEVICE_PRIMARY) {
            Hwcomposer::getInstance().getDrm()->setDpmsMode(
            IDisplayDevice::DEVICE_PRIMARY,
                IDisplayDevice::DEVICE_DISPLAY_STANDBY);
        ETRACE("primary display is source of vsync, we only dim backlight");
        return;
    }

    // panel can't be powered off as touch panel shares the power supply with LCD.
    DTRACE("primary display coupled with touch on Saltbay, only dim backlight");
    Hwcomposer::getInstance().getDrm()->setDpmsMode(
               IDisplayDevice::DEVICE_PRIMARY,
               IDisplayDevice::DEVICE_DISPLAY_STANDBY);
               //IDisplayDevice::DEVICE_DISPLAY_OFF);
    return;
}


void DisplayAnalyzer::handleIdleEntryEvent(int count)
{
    DTRACE("handling idle entry event, count %d", count);
    if (hasProtectedLayer()) {
        ITRACE("Ignoring idle entry as protected layer exists.");
        setCompositionType(0, HWC_FRAMEBUFFER, true);
        return;
    }

    // stop idle entry if external device is connected
    if (mCachedDisplays && mCachedDisplays[IDisplayDevice::DEVICE_EXTERNAL]) {
        ITRACE("Ignoring idle entry as external device is connected.");
        setCompositionType(0, HWC_FRAMEBUFFER, true);
        return;
    }

    // stop idle entry if video playback is active
    // TODO: remove this check for Annidale
    if (mVideoStateMap.size() > 0) {
        ITRACE("Ignoring idle entry as video session is active.");
        setCompositionType(0, HWC_FRAMEBUFFER, true);
        return;
    }

    setCompositionType(0, HWC_FORCE_FRAMEBUFFER, true);

    // next prepare/set will exit idle state.
    Event e;
    e.type = IDLE_EXIT_EVENT;
    postEvent(e);
}

void DisplayAnalyzer::handleIdleExitEvent()
{
    DTRACE("handling idle exit event");

    setCompositionType(0, HWC_FRAMEBUFFER, true);
}

void DisplayAnalyzer::handleVideoCheckEvent()
{
    // check if the first seen video layer on secondary device (HDMI/WFD) is marked as skipped
    // it is assumed video is always skipped if the first seen video layer is skipped
    // this is to workaround secure video layer transmitted over non secure output
    // and HWC_SKIP_LAYER set during rotation animation.
    mIgnoreVideoSkipFlag = false;

    if (mVideoStateMap.size() != 1 ||
        mCachedNumDisplays <= 1) {
        return;
    }

    intptr_t videoHandles[mCachedNumDisplays];
    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
        videoHandles[i] = 0;
        hwc_display_contents_1_t *content = mCachedDisplays[i];
        if (content == NULL) {
            continue;
        }
        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
            if (isVideoLayer(content->hwLayers[j])) {
                videoHandles[i] = (intptr_t)content->hwLayers[j].handle;
                if (i > 0) {
                    mIgnoreVideoSkipFlag = !(content->hwLayers[j].flags & HWC_SKIP_LAYER);
                    ITRACE("Ignoring video HWC_SKIP_LAYER: %d on output %d", mIgnoreVideoSkipFlag, i);
                    return;
                }
                break;
            }
        }
    }

    if (videoHandles[0]) {
        WTRACE("Video is on the primary panel only");
        return;
    }

    // video state map indicates video session is active and there is secondary
    // display, need to continue checking as video is not found in the buffers yet
    Event e;
    e.type = VIDEO_CHECK_EVENT;
    postEvent(e);
}

void DisplayAnalyzer::enterVideoExtMode()
{
    if (mVideoExtModeActive) {
        WTRACE("already in video extended mode.");
        return;
    }

    ITRACE("entering video extended mode...");
    mVideoExtModeActive = true;
    Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource();

    setCompositionType(0, HWC_OVERLAY, true);

    // Do not power off primary display immediately as flip is asynchronous
    Event e;
    e.type = DPMS_EVENT;
    e.nValue = 0;
    postEvent(e);
    Hwcomposer::getInstance().invalidate();
}

void DisplayAnalyzer::exitVideoExtMode()
{
    if (!mVideoExtModeActive) {
        WTRACE("Not in video extended mode");
        return;
    }

    ITRACE("exiting video extended mode...");

    mVideoExtModeActive = false;

    Hwcomposer::getInstance().getDrm()->setDpmsMode(
        IDisplayDevice::DEVICE_PRIMARY,
        IDisplayDevice::DEVICE_DISPLAY_ON);

    Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource();

    setCompositionType(0, HWC_FRAMEBUFFER, true);
}

bool DisplayAnalyzer::isPresentationLayer(hwc_layer_1_t &layer)
{
    if (layer.handle == NULL) {
        return false;
    }
    if (mCachedDisplays == NULL) {
        return false;
    }
    // check if the given layer exists in the primary device
    hwc_display_contents_1_t *content = mCachedDisplays[0];
    if (content == NULL) {
        return false;
    }
    for (size_t i = 0; i < content->numHwLayers - 1; i++) {
        if (content->hwLayers[i].handle == layer.handle) {
            VTRACE("Layer exists for Primary device");
            return false;
        }
    }
    return true;
}

bool DisplayAnalyzer::hasProtectedLayer()
{
    DataBuffer * buffer = NULL;
    hwc_display_contents_1_t *content = NULL;
    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();

    if (bm == NULL){
        return false;
    }

    if (mCachedDisplays == NULL) {
        return false;
    }
    // check if the given layer exists in the primary device
    for (int index = 0; index < (int)mCachedNumDisplays; index++) {
        content = mCachedDisplays[index];
        if (content == NULL) {
            continue;
        }

        for (size_t i = 0; i < content->numHwLayers - 1; i++) {
            if (isProtectedLayer(content->hwLayers[i]))
                return true;
        }
    }

    return false;
}

bool DisplayAnalyzer::isProtectedLayer(hwc_layer_1_t &layer)
{
    if (!layer.handle) {
        return false;
    }
    bool ret = false;
    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
    DataBuffer *buffer = bm->lockDataBuffer(layer.handle);
    if (!buffer) {
        ETRACE("failed to get buffer");
    } else {
        ret = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer);
        bm->unlockDataBuffer(buffer);
    }
    return ret;
}

bool DisplayAnalyzer::ignoreVideoSkipFlag()
{
    return mIgnoreVideoSkipFlag;
}

void DisplayAnalyzer::setCompositionType(hwc_display_contents_1_t *display, int type)
{
    for (size_t i = 0; i < display->numHwLayers - 1; i++) {
        hwc_layer_1_t *layer = &display->hwLayers[i];
        if (layer) layer->compositionType = type;
    }
}

void DisplayAnalyzer::setCompositionType(int device, int type, bool reset)
{
    hwc_display_contents_1_t *content = mCachedDisplays[device];
    if (content == NULL) {
        ETRACE("Invalid device %d", device);
        return;
    }

    // don't need to set geometry changed if layers are just needed to be marked
    if (reset) {
        content->flags |= HWC_GEOMETRY_CHANGED;
    }

    setCompositionType(content, type);
}

int DisplayAnalyzer::getFirstVideoInstanceSessionID() {
    if (mVideoStateMap.size() >= 1) {
        return mVideoStateMap.keyAt(0);
    }
    return -1;
}

} // namespace intel
} // namespace android