Serializing display lists

This is a WIP prototype

Change-Id: Id4bfcf2b7bf905221c3734b7b6887c9b2efd37e6
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 7cb7738..1673802 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -26,15 +26,22 @@
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
 #include "renderstate/Stencil.h"
+#include "protos/hwui.pb.h"
+
+#include <cutils/properties.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <private/hwui/DrawGlInfo.h>
+#include <strings.h>
 
 #include <algorithm>
-#include <strings.h>
-#include <cutils/properties.h>
-#include <private/hwui/DrawGlInfo.h>
+#include <fcntl.h>
+#include <sys/stat.h>
 
 #define TRIM_MEMORY_COMPLETE 80
 #define TRIM_MEMORY_UI_HIDDEN 20
 
+#define ENABLE_RENDERNODE_SERIALIZATION false
+
 #define LOG_FRAMETIME_MMA 0
 
 #if LOG_FRAMETIME_MMA
@@ -480,6 +487,40 @@
     mRenderThread.jankTracker().reset();
 }
 
+void CanvasContext::serializeDisplayListTree() {
+#if ENABLE_RENDERNODE_SERIALIZATION
+    using namespace google::protobuf::io;
+    char package[128];
+    // Check whether tracing is enabled for this process.
+    FILE * file = fopen("/proc/self/cmdline", "r");
+    if (file) {
+        if (!fgets(package, 128, file)) {
+            ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
+            fclose(file);
+            return;
+        }
+        fclose(file);
+    } else {
+        ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
+                errno);
+        return;
+    }
+    char path[1024];
+    snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package);
+    int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH);
+    if (fd == -1) {
+        ALOGD("Failed to open '%s'", path);
+        return;
+    }
+    proto::RenderNode tree;
+    // TODO: Streaming writes?
+    mRootRenderNode->copyTo(&tree);
+    std::string data = tree.SerializeAsString();
+    write(fd, data.c_str(), data.length());
+    close(fd);
+#endif
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0ceb9f1..6a79320 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -111,6 +111,8 @@
     void setName(const std::string&& name) { mName = name; }
     const std::string& name() { return mName; }
 
+    void serializeDisplayListTree();
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a3a0163..b838811 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -490,6 +490,17 @@
     post(task);
 }
 
+CREATE_BRIDGE1(serializeDisplayListTree, CanvasContext* context) {
+    args->context->serializeDisplayListTree();
+    return nullptr;
+}
+
+void RenderProxy::serializeDisplayListTree() {
+    SETUP_TASK(serializeDisplayListTree);
+    args->context = mContext;
+    post(task);
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 0d2c7be..e7356db 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -104,6 +104,8 @@
     ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
     ANDROID_API void setProcessStatsBuffer(int fd);
 
+    ANDROID_API void serializeDisplayListTree();
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;