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
This commit is contained in:
Dileep Marchya 2015-12-03 14:39:35 -08:00 committed by Steve Kondik
parent 0e898965c3
commit a9cbaf5097
5 changed files with 131 additions and 0 deletions

View File

@ -39,6 +39,11 @@ LOCAL_SRC_FILES := \
DisplayUtils.cpp
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
LOCAL_CFLAGS += -DDEBUG_CONT_DUMPSYS
endif
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
ifeq ($(TARGET_BOARD_PLATFORM),omap4)

View File

@ -28,6 +28,7 @@
#include "ExSurfaceFlinger.h"
#include "ExLayer.h"
#include <fstream>
#include <cutils/properties.h>
#ifdef QTI_BSP
#include <hardware/display_defs.h>
@ -266,4 +267,110 @@ void ExSurfaceFlinger::drawWormHoleIfRequired(HWComposer::LayerListIterator& cur
}
}
#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

View File

@ -79,6 +79,20 @@ protected:
bool mDebugLogs;
bool isDebug() { return mDebugLogs; }
bool mDisableExtAnimation;
#ifdef DEBUG_CONT_DUMPSYS
virtual status_t dump(int fd, const Vector<String16>& args);
virtual void dumpDrawCycle(bool prePrepare );
struct {
Mutex lock;
const char *name = "/data/misc/display/dumpsys.txt";
bool running = false;
bool noLimit = false;
bool replaceAfterCommit = false;
long int position = 0;
} mFileDump;
#endif
};
}; //namespace android

View File

@ -1081,6 +1081,8 @@ void SurfaceFlinger::postComposition()
mAnimFrameTracker.advanceFrame();
}
dumpDrawCycle(false);
if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
return;
}
@ -1248,6 +1250,8 @@ void SurfaceFlinger::setUpHWComposer() {
}
}
dumpDrawCycle(true);
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));

View File

@ -471,6 +471,7 @@ private:
void logFrameStats();
void dumpStaticScreenStats(String8& result) const;
virtual void dumpDrawCycle(bool /* prePrepare */ ) { }
/* ------------------------------------------------------------------------
* Attributes