Move SF trace logging into a separate thread

SF trace logging currently happens on the main thread, which affects
performance. Move it to a separate thread to mitigate the overhead.

Use a lock to prevent the drawing state to be updated while it is being
dumped.

Also, allow the buffer size for SF traces to be configured. Current buffer
size is fixed to 100MB, which is unfeasible for phones with lower resources.

Created option 1029 to manually update the buffer size.
To trigger the option use:
- adb shell su root service call SurfaceFlinger 1029 i32 <SIZE>

This option trigger an "Invalid Argument" error if it receives a
negative value.

Finally, just log Winscope trace if visible regions are dirty. SF
currently logs all Winscope frames. It should log only if there is a
change to mitigate resource consumption.

Test: Flash a device. Start a trace. Run systrace. Record a trace. Check
if the `commitTransaction` trace happens in a separate SF thread and
doesn't block the critical path

Change-Id: Ie05ad5c025a185b28209bbc5d26655ba9ff9042b
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index b7e9a91..f1c4347 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -18,6 +18,7 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "SurfaceTracing.h"
+#include <SurfaceFlinger.h>
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -27,6 +28,48 @@
 
 namespace android {
 
+void SurfaceTracing::mainLoop() {
+    bool enabled = true;
+    // Upon activation, logs the first frame
+    traceLayers("tracing.enable");
+    do {
+        std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
+        mConditionalVariable.wait(sfLock);
+        LayersTraceProto entry = traceLayersLocked(mWhere);
+        sfLock.unlock();
+        {
+            std::scoped_lock bufferLock(mTraceLock);
+            mBuffer.emplace(std::move(entry));
+            if (mWriteToFile) {
+                writeProtoFileLocked();
+                mWriteToFile = false;
+            }
+
+            enabled = mEnabled;
+        }
+    } while (enabled);
+}
+
+void SurfaceTracing::traceLayers(const char* where) {
+    std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
+    LayersTraceProto entry = traceLayersLocked(where);
+    sfLock.unlock();
+    std::scoped_lock bufferLock(mTraceLock);
+    mBuffer.emplace(std::move(entry));
+}
+
+void SurfaceTracing::notify(const char* where) {
+    std::lock_guard<std::mutex> sfLock(mFlinger.mDrawingStateLock);
+    mWhere = strdup(where);
+    mConditionalVariable.notify_one();
+}
+
+void SurfaceTracing::writeToFileAsync() {
+    std::lock_guard<std::mutex> bufferLock(mTraceLock);
+    mWriteToFile = true;
+    mConditionalVariable.notify_one();
+}
+
 void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
     // use the swap trick to make sure memory is released
     std::queue<LayersTraceProto>().swap(mStorage);
@@ -58,50 +101,60 @@
     }
 }
 
-void SurfaceTracing::enable(size_t bufferSizeInByte) {
-    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+void SurfaceTracing::enable() {
+    std::lock_guard<std::mutex> bufferLock(mTraceLock);
 
     if (mEnabled) {
         return;
     }
+
+    mBuffer.reset(mBufferSize);
     mEnabled = true;
-    mBuffer.reset(bufferSizeInByte);
+    mThread = std::thread(&SurfaceTracing::mainLoop, this);
 }
 
-status_t SurfaceTracing::disable() {
-    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+status_t SurfaceTracing::writeToFile() {
+    mThread.join();
+    return mLastErr;
+}
+
+bool SurfaceTracing::disable() {
+    std::lock_guard<std::mutex> bufferLock(mTraceLock);
 
     if (!mEnabled) {
-        return NO_ERROR;
+        return false;
     }
+
     mEnabled = false;
-    status_t err(writeProtoFileLocked());
-    ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
-    ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
-    mBuffer.reset(0);
-    return err;
+    mWriteToFile = true;
+    mConditionalVariable.notify_all();
+    return true;
 }
 
 bool SurfaceTracing::isEnabled() const {
-    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+    std::lock_guard<std::mutex> bufferLock(mTraceLock);
     return mEnabled;
 }
 
-void SurfaceTracing::traceLayers(const char* where, LayersProto layers) {
-    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
-    if (!mEnabled) {
-        return;
-    }
+void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
+    std::lock_guard<std::mutex> bufferLock(mTraceLock);
+    mBufferSize = bufferSizeInByte;
+    mBuffer.setSize(bufferSizeInByte);
+}
+
+LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
+    ATRACE_CALL();
 
     LayersTraceProto entry;
     entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
     entry.set_where(where);
+    LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing));
     entry.mutable_layers()->Swap(&layers);
 
-    mBuffer.emplace(std::move(entry));
+    return entry;
 }
 
-status_t SurfaceTracing::writeProtoFileLocked() {
+void SurfaceTracing::writeProtoFileLocked() {
     ATRACE_CALL();
 
     LayersTraceFileProto fileProto;
@@ -110,19 +163,23 @@
     fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
                                LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
     mBuffer.flush(&fileProto);
+    mBuffer.reset(mBufferSize);
 
     if (!fileProto.SerializeToString(&output)) {
-        return PERMISSION_DENIED;
+        ALOGE("Could not save the proto file! Permission denied");
+        mLastErr = PERMISSION_DENIED;
     }
-    if (!android::base::WriteStringToFile(output, kDefaultFileName, true)) {
-        return PERMISSION_DENIED;
+    if (!android::base::WriteStringToFile(output, kDefaultFileName, S_IRWXU | S_IRGRP, getuid(),
+                                          getgid(), true)) {
+        ALOGE("Could not save the proto file! There are missing fields");
+        mLastErr = PERMISSION_DENIED;
     }
 
-    return NO_ERROR;
+    mLastErr = NO_ERROR;
 }
 
 void SurfaceTracing::dump(std::string& result) const {
-    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+    std::lock_guard<std::mutex> bufferLock(mTraceLock);
 
     base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
     base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",