Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee88d8dd authored by Dileep Marchya's avatar Dileep Marchya Committed by Linux Build Service Account
Browse files

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
parent f44e020b
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -48,6 +48,11 @@ LOCAL_C_INCLUDES := \
	external/vulkan-validation-layers/libs/vkjson

LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"

ifeq ($(TARGET_BUILD_VARIANT),userdebug)
LOCAL_CFLAGS += -DDEBUG_CONT_DUMPSYS
endif

LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
#LOCAL_CFLAGS += -DENABLE_FENCE_TRACKING

+107 −0
Original line number Diff line number Diff line
@@ -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
+14 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -466,6 +466,7 @@ private:
    void logFrameStats();

    void dumpStaticScreenStats(String8& result) const;
    virtual void dumpDrawCycle(bool /* prePrepare */ ) { }

    /* ------------------------------------------------------------------------
     * Attributes
+4 −0
Original line number Diff line number Diff line
@@ -1091,6 +1091,8 @@ void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
        mAnimFrameTracker.advanceFrame();
    }

    dumpDrawCycle(true);

    if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
        return;
    }
@@ -1254,6 +1256,8 @@ void SurfaceFlinger::setUpHWComposer() {
            }
        }

        dumpDrawCycle(true);

        status_t err = hwc.prepare();
        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));