OSDN Git Service

SurfaceFlinger: Add support for continuous dumpsys to file.
authorDileep Marchya <dmarchya@codeaurora.org>
Thu, 3 Dec 2015 22:39:35 +0000 (14:39 -0800)
committerSteve Kondik <steve@cyngn.com>
Sun, 13 Mar 2016 10:28:46 +0000 (03:28 -0700)
- 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

services/surfaceflinger/Android.mk
services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp
services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.h
services/surfaceflinger/SurfaceFlinger.cpp
services/surfaceflinger/SurfaceFlinger.h

index 37ad4ac..c1ddba1 100644 (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)
index 0014e80..96d4b1d 100644 (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
index 628fac7..068f2b9 100644 (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
index 43a0bd8..a457019 100644 (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));
 
index 2028d67..1f7601a 100644 (file)
@@ -471,6 +471,7 @@ private:
     void logFrameStats();
 
     void dumpStaticScreenStats(String8& result) const;
+    virtual void dumpDrawCycle(bool /* prePrepare */ ) { }
 
     /* ------------------------------------------------------------------------
      * Attributes