replicant-frameworks_native/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp
Dileep Marchya a9cbaf5097 SurfaceFlinger: Add support for continuous dumpsys to file.
- Collect dumpsys to an outfile file when triggered.
- Collect dumpsys before calling Prepare on hwc module in
  each draw cycle. Recollect dumpsys if Commit goes through
  successfully and replace former dumpsys with this.
- Wrap around if file size reaches appx 20 MB.
- Generate output file at /data/misc/display/dumpsys.txt
- Syntax:
      adb shell dumpsys SurfaceFlinger --file [--no-limit]
          --file : Ouput dumpsys to file
          --no-limit : Do not wrap around, keep appending

      Use same command to trigger start and end of dumping.
- Output format:
      | start code | after commit? | time stamp | dump size | dump data |

CRs-Fixed: 947084

Change-Id: Ie520f51c69757aeec88b9400688a7f3271472349
2016-03-13 03:28:46 -07:00

377 lines
13 KiB
C++

/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ExSurfaceFlinger.h"
#include "ExLayer.h"
#include <fstream>
#include <cutils/properties.h>
#ifdef QTI_BSP
#include <hardware/display_defs.h>
#endif
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
namespace android {
bool ExSurfaceFlinger::sExtendedMode = false;
ExSurfaceFlinger::ExSurfaceFlinger() {
char property[PROPERTY_VALUE_MAX] = {0};
mDebugLogs = false;
if((property_get("persist.debug.qdframework.logs", property, NULL) > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
mDebugLogs = true;
}
ALOGD_IF(isDebug(),"Creating custom SurfaceFlinger %s",__FUNCTION__);
mDisableExtAnimation = false;
if((property_get("sys.disable_ext_animation", property, "0") > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
mDisableExtAnimation = true;
}
ALOGD_IF(isDebug(),"Animation on external is %s in %s",
mDisableExtAnimation ? "disabled" : "not disabled", __FUNCTION__);
}
ExSurfaceFlinger::~ExSurfaceFlinger() { }
void ExSurfaceFlinger::updateExtendedMode() {
char prop[PROPERTY_VALUE_MAX];
property_get("sys.extended_mode", prop, "0");
sExtendedMode = atoi(prop) ? true : false;
}
void ExSurfaceFlinger::getIndexLOI(size_t dpy,
const LayerVector& currentLayers,
bool& bIgnoreLayers,
int& indexLOI ) {
size_t i = currentLayers.size();
while(i--) {
const sp<Layer>& layer = currentLayers[i];
/* iterate through the layer list to find ext_only layers and store
* the index
*/
if (layer->isSecureDisplay()) {
bIgnoreLayers = true;
indexLOI = -1;
if(!dpy)
indexLOI = i;
break;
}
/* iterate through the layer list to find ext_only layers or yuv
* layer(extended_mode) and store the index
*/
if ((dpy && (layer->isExtOnly() ||
(isExtendedMode() && layer->isYuvLayer())))) {
bIgnoreLayers= true;
indexLOI = i;
}
}
return;
}
bool ExSurfaceFlinger::updateLayerVisibleNonTransparentRegion(
const int& dpy, const sp<Layer>& layer,
bool& bIgnoreLayers, int& indexLOI,
uint32_t layerStack, const int& i) {
const Layer::State& s(layer->getDrawingState());
/* Only add the layer marked as "external_only" or yuvLayer
* (extended_mode) to external list and
* only remove the layer marked as "external_only" or yuvLayer in
* extended_mode from primary list
* and do not add the layer marked as "internal_only" to external list
* Add secure UI layers to primary and remove other layers from internal
* and external list
*/
if(((bIgnoreLayers && indexLOI != (int)i) ||
(!dpy && layer->isExtOnly()) ||
(!dpy && isExtendedMode() && layer->isYuvLayer()))||
(dpy && layer->isIntOnly())) {
/* Ignore all other layers except the layers marked as ext_only
* by setting visible non transparent region empty
*/
Region visibleNonTransRegion;
visibleNonTransRegion.set(Rect(0,0));
layer->setVisibleNonTransparentRegion(visibleNonTransRegion);
return true;
}
/* only consider the layers on the given later stack
* Override layers created using presentation class by the layers having
* ext_only flag enabled
*/
if(s.layerStack != layerStack && !bIgnoreLayers) {
/* set the visible region as empty since we have removed the
* layerstack check in rebuildLayerStack() function
*/
Region visibleNonTransRegion;
visibleNonTransRegion.set(Rect(0,0));
layer->setVisibleNonTransparentRegion(visibleNonTransRegion);
return true;
}
if (mDisableExtAnimation) {
/* Remove screenShotSurface from secondary displays when ext animation disabled */
const int screenShotLen = strlen("ScreenshotSurface");
if (dpy && !strncmp(layer->getName(), "ScreenshotSurface", screenShotLen) ) {
Region visibleNonTransRegion;
visibleNonTransRegion.set(Rect(0, 0));
layer->setVisibleNonTransparentRegion(visibleNonTransRegion);
return true;
}
}
return false;
}
void ExSurfaceFlinger::delayDPTransactionIfNeeded(
const Vector<DisplayState>& displays) {
/* Delay the display projection transaction by 50ms only when the disable
* external rotation animation feature is enabled
*/
if(mDisableExtAnimation) {
size_t count = displays.size();
for (size_t i=0 ; i<count ; i++) {
const DisplayState& s(displays[i]);
if((mDisplays.indexOfKey(s.token) >= 0) && (s.token !=
mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])) {
const uint32_t what = s.what;
/* Invalidate and Delay the binder thread by 50 ms on
* eDisplayProjectionChanged to trigger a draw cycle so that
* it can fix one incorrect frame on the External, when we
* disable external animation
*/
if (what & DisplayState::eDisplayProjectionChanged) {
invalidateHwcGeometry();
repaintEverything();
usleep(50000);
}
}
}
}
}
bool ExSurfaceFlinger::canDrawLayerinScreenShot(
const sp<const DisplayDevice>& hw,
const sp<Layer>& layer) {
int dispType = hw->getDisplayType();
/* a) Don't draw SecureDisplayLayer or ProtectedLayer.
* b) Don't let ext_only and extended_mode to be captured
* If not, we would see incorrect image during rotation
* on primary.
*/
if(!layer->isSecureDisplay()
&& !layer->isProtected()
&& !(!dispType && (layer->isExtOnly() ||
(isExtendedMode() && layer->isYuvLayer())))
&& !(layer->isIntOnly() && dispType)
&& layer->isVisible()){
return true;
}
return false;
}
void ExSurfaceFlinger::isfreezeSurfacePresent(bool& freezeSurfacePresent,
const sp<const DisplayDevice>& hw,
const int32_t& id) {
freezeSurfacePresent = false;
/* Get the layers in the current drawing state */
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t layerCount = layers.size();
/* Look for ScreenShotSurface in external layer list, only when
* disable external rotation animation feature is enabled
*/
if(mDisableExtAnimation && (id != HWC_DISPLAY_PRIMARY)) {
for (size_t i = 0 ; i < layerCount ; ++i) {
static int screenShotLen = strlen("ScreenshotSurface");
const sp<Layer>& layer(layers[i]);
const Layer::State& s(layer->getDrawingState());
/* check the layers associated with external display */
if(s.layerStack == hw->getLayerStack()) {
if(!strncmp(layer->getName(), "ScreenshotSurface",
screenShotLen)) {
/* Screenshot layer is present, and animation in
* progress
*/
freezeSurfacePresent = true;
break;
}
}
}
}
}
void ExSurfaceFlinger::setOrientationEventControl(bool& freezeSurfacePresent,
const int32_t& id) {
HWComposer& hwc(getHwComposer());
HWComposer::LayerListIterator cur = hwc.begin(id);
if(freezeSurfacePresent) {
/* If freezeSurfacePresent, set ANIMATING flag
* which is used to support disable animation on external
*/
cur->setAnimating(true);
}
}
void ExSurfaceFlinger::updateVisibleRegionsDirty() {
/* If extended_mode is set, and set mVisibleRegionsDirty
* as we need to rebuildLayerStack
*/
if(isExtendedMode()) {
mVisibleRegionsDirty = true;
}
}
void ExSurfaceFlinger::drawWormHoleIfRequired(HWComposer::LayerListIterator& cur,
const HWComposer::LayerListIterator& end,
const sp<const DisplayDevice>& hw,
const Region& region) {
if (cur != end) {
#ifdef QTI_BSP
if (cur->getCompositionType() != HWC_BLIT)
drawWormhole(hw, region);
#endif
} else {
drawWormhole(hw, region);
}
}
#ifdef DEBUG_CONT_DUMPSYS
status_t ExSurfaceFlinger::dump(int fd, const Vector<String16>& args) {
// Format: adb shell dumpsys SurfaceFlinger --file --no-limit
size_t numArgs = args.size();
status_t err = NO_ERROR;
if (!numArgs || (args[0] != String16("--file"))) {
return SurfaceFlinger::dump(fd, args);
}
Mutex::Autolock _l(mFileDump.lock);
// Same command is used to start and end dump.
mFileDump.running = !mFileDump.running;
if (mFileDump.running) {
// Create an empty file or erase existing file.
std::fstream fs;
fs.open(mFileDump.name, std::ios::out);
if (!fs) {
mFileDump.running = false;
err = UNKNOWN_ERROR;
} else {
mFileDump.position = 0;
if (numArgs >= 2 && (args[1] == String16("--nolimit"))) {
mFileDump.noLimit = true;
} else {
mFileDump.noLimit = false;
}
}
}
String8 result;
result += mFileDump.running ? "Start" : "End";
result += mFileDump.noLimit ? " unlimited" : " fixed limit";
result += " dumpsys to file : ";
result += mFileDump.name;
result += "\n";
write(fd, result.string(), result.size());
return NO_ERROR;
}
void ExSurfaceFlinger::dumpDrawCycle(bool prePrepare) {
Mutex::Autolock _l(mFileDump.lock);
// User might stop dump collection in middle of prepare & commit.
// Collect dumpsys again after commit and replace.
if (!mFileDump.running && !mFileDump.replaceAfterCommit) {
return;
}
Vector<String16> args;
size_t index = 0;
String8 dumpsys;
dumpAllLocked(args, index, dumpsys);
char timeStamp[32];
char dataSize[32];
char hms[32];
long millis;
struct timeval tv;
struct tm *ptm;
gettimeofday(&tv, NULL);
ptm = localtime(&tv.tv_sec);
strftime (hms, sizeof (hms), "%H:%M:%S", ptm);
millis = tv.tv_usec / 1000;
snprintf(timeStamp, sizeof(timeStamp), "Timestamp: %s.%03ld", hms, millis);
snprintf(dataSize, sizeof(dataSize), "Size: %8zu", dumpsys.size());
std::fstream fs;
fs.open(mFileDump.name, std::ios::in | std::ios::out);
if (!fs) {
ALOGE("Failed to open %s file for dumpsys", mFileDump.name);
return;
}
// Format:
// | start code | after commit? | time stamp | dump size | dump data |
fs.seekp(mFileDump.position, std::ios::beg);
fs << "#@#@-- DUMPSYS START --@#@#" << std::endl;
fs << "PostCommit: " << ( prePrepare ? "false" : "true" ) << std::endl;
fs << timeStamp << std::endl;
fs << dataSize << std::endl;
fs << dumpsys << std::endl;
if (prePrepare) {
mFileDump.replaceAfterCommit = true;
} else {
mFileDump.replaceAfterCommit = false;
// Reposition only after commit.
// Keem file size to appx 20 MB limit by default, wrap around if exceeds.
mFileDump.position = fs.tellp();
if (!mFileDump.noLimit && (mFileDump.position > (20 * 1024 * 1024))) {
mFileDump.position = 0;
}
}
fs.close();
}
#endif
}; // namespace android