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;