Switch to protobuf lite

Fixes: 36272398

Protobuf lite isn't just smaller, it also doesn't
have the problematic DescriptorPool at all. So no
need to switch this to a shared library.

Test: hwui_unit_test passes and doesn't crash. CTS incident tests pass
as well

Change-Id: I2693ba2c47af89a5c561c4f63cc7e1f509ebbbec
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index ab6420e..87eaa6a 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -19,7 +19,7 @@
 #include "JankTracker.h"
 
 #include <frameworks/base/core/proto/android/service/graphicsstats.pb.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <log/log.h>
 
 #include <inttypes.h>
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <sys/mman.h>
 
 namespace android {
 namespace uirenderer {
@@ -46,10 +47,74 @@
         const ProfileData* data);
 static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
 
+class FileDescriptor {
+public:
+    FileDescriptor(int fd) : mFd(fd) {}
+    ~FileDescriptor() {
+        if (mFd != -1) {
+            close(mFd);
+            mFd = -1;
+        }
+    }
+    bool valid() { return mFd != -1; }
+    operator int() { return mFd; }
+private:
+    int mFd;
+};
+
+class FileOutputStreamLite : public io::ZeroCopyOutputStream {
+public:
+    FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {}
+    virtual ~FileOutputStreamLite() {}
+
+    int GetErrno() { return mCopyAdapter.mErrno; }
+
+    virtual bool Next(void** data, int* size) override {
+        return mImpl.Next(data, size);
+    }
+
+    virtual void BackUp(int count) override {
+        mImpl.BackUp(count);
+    }
+
+    virtual int64 ByteCount() const override {
+        return mImpl.ByteCount();
+    }
+
+    bool Flush() {
+        return mImpl.Flush();
+    }
+
+private:
+    struct FDAdapter : public io::CopyingOutputStream {
+        int mFd;
+        int mErrno = 0;
+
+        FDAdapter(int fd) : mFd(fd) {}
+        virtual ~FDAdapter() {}
+
+        virtual bool Write(const void* buffer, int size) override {
+            int ret;
+            while (size) {
+                ret = TEMP_FAILURE_RETRY( write(mFd, buffer, size) );
+                if (ret <= 0) {
+                    mErrno = errno;
+                    return false;
+                }
+                size -= ret;
+            }
+            return true;
+        }
+    };
+
+    FileOutputStreamLite::FDAdapter mCopyAdapter;
+    io::CopyingOutputStreamAdaptor mImpl;
+};
+
 bool GraphicsStatsService::parseFromFile(const std::string& path, service::GraphicsStatsProto* output) {
 
-    int fd = open(path.c_str(), O_RDONLY);
-    if (fd == -1) {
+    FileDescriptor fd{open(path.c_str(), O_RDONLY)};
+    if (!fd.valid()) {
         int err = errno;
         // The file not existing is normal for addToDump(), so only log if
         // we get an unexpected error
@@ -58,26 +123,41 @@
         }
         return false;
     }
-    uint32_t file_version;
-    ssize_t bytesRead = read(fd, &file_version, sHeaderSize);
-    if (bytesRead != sHeaderSize || file_version != sCurrentFileVersion) {
-        ALOGW("Failed to read '%s', bytesRead=%zd file_version=%d", path.c_str(), bytesRead,
-                file_version);
-        close(fd);
+    struct stat sb;
+    if (fstat(fd, &sb) || sb.st_size < sHeaderSize) {
+        int err = errno;
+        // The file not existing is normal for addToDump(), so only log if
+        // we get an unexpected error
+        if (err != ENOENT) {
+            ALOGW("Failed to fstat '%s', errno=%d (%s) (st_size %d)", path.c_str(), err,
+                    strerror(err), (int) sb.st_size);
+        }
+        return false;
+    }
+    void* addr = mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    if (!addr) {
+        int err = errno;
+        // The file not existing is normal for addToDump(), so only log if
+        // we get an unexpected error
+        if (err != ENOENT) {
+            ALOGW("Failed to mmap '%s', errno=%d (%s)", path.c_str(), err, strerror(err));
+        }
+        return false;
+    }
+    uint32_t file_version = *reinterpret_cast<uint32_t*>(addr);
+    if (file_version != sCurrentFileVersion) {
+        ALOGW("file_version mismatch! expected %d got %d", sCurrentFileVersion, file_version);
         return false;
     }
 
-    io::FileInputStream input(fd);
+    void* data = reinterpret_cast<uint8_t*>(addr) + sHeaderSize;
+    int dataSize = sb.st_size - sHeaderSize;
+    io::ArrayInputStream input{data, dataSize};
     bool success = output->ParseFromZeroCopyStream(&input);
-    if (input.GetErrno() != 0) {
-        ALOGW("Error reading from fd=%d, path='%s' err=%d (%s)",
-                fd, path.c_str(), input.GetErrno(), strerror(input.GetErrno()));
-        success = false;
-    } else if (!success) {
+    if (!success) {
         ALOGW("Parse failed on '%s' error='%s'",
                 path.c_str(), output->InitializationErrorString().c_str());
     }
-    close(fd);
     return success;
 }
 
@@ -212,7 +292,7 @@
         return;
     }
     {
-        io::FileOutputStream output(outFd);
+        FileOutputStreamLite output(outFd);
         bool success = statsProto.SerializeToZeroCopyStream(&output) && output.Flush();
         if (output.GetErrno() != 0) {
             ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)",
@@ -277,7 +357,7 @@
 
 void GraphicsStatsService::finishDump(Dump* dump) {
     if (dump->type() == DumpType::Protobuf) {
-        io::FileOutputStream stream(dump->fd());
+        FileOutputStreamLite stream(dump->fd());
         dump->proto().SerializeToZeroCopyStream(&stream);
     }
     delete dump;