diff --git a/Android.bp b/Android.bp index 4ab5f1f2c43b2..5c059b54ffac5 100644 --- a/Android.bp +++ b/Android.bp @@ -28,26 +28,26 @@ cc_library { proto: { type: "full", }, + srcs: [ + "core/proto/**/*.proto", + "libs/incident/**/*.proto", + ], }, android: { proto: { type: "lite", }, + // We only build the protos that are optimized for the lite + // runtime, as well as the only protos that are actually + // needed by the device. + srcs: [ + "core/proto/android/service/graphicsstats.proto", + ], shared: { - // The proto files generate full protos, but we only use - // them as lite on device. This works fine for a static - // library, where the unused full symbols are stripped, - // but fails if it is linked as a standalone shared - // library because it is missing the full runtime. enabled: false, }, }, }, - - srcs: [ - "core/proto/**/*.proto", - "libs/incident/**/*.proto", - ], } subdirs = [ diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index 2042bf62ad4cc..0ee71bda9ddde 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -22,7 +22,6 @@ option java_outer_classname = "IncidentProtoMetadata"; import "frameworks/base/libs/incident/proto/android/privacy.proto"; import "frameworks/base/core/proto/android/service/appwidget.proto"; import "frameworks/base/core/proto/android/service/battery.proto"; -import "frameworks/base/core/proto/android/service/graphicsstats.proto"; import "frameworks/base/core/proto/android/service/fingerprint.proto"; import "frameworks/base/core/proto/android/service/diskstats.proto"; import "frameworks/base/core/proto/android/service/netstats.proto"; @@ -66,5 +65,4 @@ message IncidentProto { android.service.notification.NotificationServiceDumpProto notification = 3004; android.service.pm.PackageServiceDumpProto package = 3008; android.service.power.PowerServiceDumpProto power = 3009; - android.service.GraphicsStatsServiceDumpProto graphicsstats = 3005; } diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto index 6dbfe4850892f..b8679b0d03a3f 100644 --- a/core/proto/android/service/graphicsstats.proto +++ b/core/proto/android/service/graphicsstats.proto @@ -20,6 +20,7 @@ package android.service; option java_multiple_files = true; option java_outer_classname = "GraphicsStatsServiceProto"; +option optimize_for = LITE_RUNTIME; message GraphicsStatsServiceDumpProto { repeated GraphicsStatsProto stats = 1; diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index acf88838efc5d..07ff27de794f0 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -62,7 +62,7 @@ cc_defaults { "libskia", "libui", "libgui", - "libprotobuf-cpp-full", + "libprotobuf-cpp-lite", "libharfbuzz_ng", "libft2", "libminikin", diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index ab6420e990f94..87eaa6add4597 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -19,7 +19,7 @@ #include "JankTracker.h" #include -#include +#include #include #include @@ -27,6 +27,7 @@ #include #include #include +#include namespace android { namespace uirenderer { @@ -46,10 +47,74 @@ static void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, 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 @@ bool GraphicsStatsService::parseFromFile(const std::string& path, service::Graph } 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(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(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 @@ void GraphicsStatsService::saveBuffer(const std::string& path, const std::string 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::addToDump(Dump* dump, const std::string& path) { 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; diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp index 773a7ea54a52a..ee202367d73e3 100644 --- a/libs/hwui/tests/unit/FontRendererTests.cpp +++ b/libs/hwui/tests/unit/FontRendererTests.cpp @@ -28,7 +28,7 @@ static bool isZero(uint8_t* data, int size) { return true; } -RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, DISABLED_renderDropShadow) { +RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) { SkPaint paint; paint.setTextSize(10); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp index 5383e5756b933..8312bda8d67d9 100644 --- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp +++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp @@ -26,7 +26,7 @@ using namespace android; using namespace android::uirenderer; -RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, DISABLED_addRemove) { +RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) { SkPaint paint; paint.setTextSize(20);