blob: 8b5912b2081ac3ac400a5458932da1ef286b645b [file] [log] [blame]
John Reckdf1742e2017-01-19 15:56:21 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "GraphicsStatsService.h"
18
19#include "JankTracker.h"
Kweku Adams1856a4c2018-04-03 16:31:10 -070020#include "protos/graphicsstats.pb.h"
John Reckdf1742e2017-01-19 15:56:21 -080021
John Reck915883b2017-05-03 10:27:20 -070022#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
John Reckdf1742e2017-01-19 15:56:21 -080023#include <log/log.h>
24
Dan Albert110e0072017-10-11 12:41:26 -070025#include <errno.h>
John Reckdf1742e2017-01-19 15:56:21 -080026#include <fcntl.h>
Dan Albert110e0072017-10-11 12:41:26 -070027#include <inttypes.h>
John Reck1bcacfd2017-11-03 10:12:19 -070028#include <sys/mman.h>
Dan Albert110e0072017-10-11 12:41:26 -070029#include <sys/stat.h>
30#include <sys/types.h>
John Reckdf1742e2017-01-19 15:56:21 -080031#include <unistd.h>
32
33namespace android {
34namespace uirenderer {
35
36using namespace google::protobuf;
37
38constexpr int32_t sCurrentFileVersion = 1;
39constexpr int32_t sHeaderSize = 4;
40static_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong");
41
John Reck7075c792017-07-05 14:03:43 -070042constexpr int sHistogramSize = ProfileData::HistogramSize();
Stan Iliev7203e1f2019-07-25 13:12:02 -040043constexpr int sGPUHistogramSize = ProfileData::GPUHistogramSize();
John Reckdf1742e2017-01-19 15:56:21 -080044
Kweku Adams1856a4c2018-04-03 16:31:10 -070045static bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto,
Dianne Hackborn73453e42017-12-11 16:30:36 -080046 const std::string& package, int64_t versionCode,
John Reck1bcacfd2017-11-03 10:12:19 -070047 int64_t startTime, int64_t endTime, const ProfileData* data);
Kweku Adams1856a4c2018-04-03 16:31:10 -070048static void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int outFd);
John Reckdf1742e2017-01-19 15:56:21 -080049
John Reck915883b2017-05-03 10:27:20 -070050class FileDescriptor {
51public:
Chih-Hung Hsiehf21b0b62018-12-20 13:48:02 -080052 explicit FileDescriptor(int fd) : mFd(fd) {}
John Reck915883b2017-05-03 10:27:20 -070053 ~FileDescriptor() {
54 if (mFd != -1) {
55 close(mFd);
56 mFd = -1;
57 }
58 }
59 bool valid() { return mFd != -1; }
Chih-Hung Hsiehf21b0b62018-12-20 13:48:02 -080060 operator int() { return mFd; } // NOLINT(google-explicit-constructor)
John Reck1bcacfd2017-11-03 10:12:19 -070061
John Reck915883b2017-05-03 10:27:20 -070062private:
63 int mFd;
64};
65
66class FileOutputStreamLite : public io::ZeroCopyOutputStream {
67public:
Chih-Hung Hsiehf21b0b62018-12-20 13:48:02 -080068 explicit FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {}
John Reck915883b2017-05-03 10:27:20 -070069 virtual ~FileOutputStreamLite() {}
70
71 int GetErrno() { return mCopyAdapter.mErrno; }
72
John Reck1bcacfd2017-11-03 10:12:19 -070073 virtual bool Next(void** data, int* size) override { return mImpl.Next(data, size); }
John Reck915883b2017-05-03 10:27:20 -070074
John Reck1bcacfd2017-11-03 10:12:19 -070075 virtual void BackUp(int count) override { mImpl.BackUp(count); }
John Reck915883b2017-05-03 10:27:20 -070076
John Reck1bcacfd2017-11-03 10:12:19 -070077 virtual int64 ByteCount() const override { return mImpl.ByteCount(); }
John Reck915883b2017-05-03 10:27:20 -070078
John Reck1bcacfd2017-11-03 10:12:19 -070079 bool Flush() { return mImpl.Flush(); }
John Reck915883b2017-05-03 10:27:20 -070080
81private:
82 struct FDAdapter : public io::CopyingOutputStream {
83 int mFd;
84 int mErrno = 0;
85
Chih-Hung Hsiehf21b0b62018-12-20 13:48:02 -080086 explicit FDAdapter(int fd) : mFd(fd) {}
John Reck915883b2017-05-03 10:27:20 -070087 virtual ~FDAdapter() {}
88
89 virtual bool Write(const void* buffer, int size) override {
90 int ret;
91 while (size) {
John Reck1bcacfd2017-11-03 10:12:19 -070092 ret = TEMP_FAILURE_RETRY(write(mFd, buffer, size));
John Reck915883b2017-05-03 10:27:20 -070093 if (ret <= 0) {
94 mErrno = errno;
95 return false;
96 }
97 size -= ret;
98 }
99 return true;
100 }
101 };
102
103 FileOutputStreamLite::FDAdapter mCopyAdapter;
104 io::CopyingOutputStreamAdaptor mImpl;
105};
106
John Reck1bcacfd2017-11-03 10:12:19 -0700107bool GraphicsStatsService::parseFromFile(const std::string& path,
Kweku Adams1856a4c2018-04-03 16:31:10 -0700108 protos::GraphicsStatsProto* output) {
John Reck915883b2017-05-03 10:27:20 -0700109 FileDescriptor fd{open(path.c_str(), O_RDONLY)};
110 if (!fd.valid()) {
John Reckdf1742e2017-01-19 15:56:21 -0800111 int err = errno;
112 // The file not existing is normal for addToDump(), so only log if
113 // we get an unexpected error
114 if (err != ENOENT) {
115 ALOGW("Failed to open '%s', errno=%d (%s)", path.c_str(), err, strerror(err));
116 }
117 return false;
118 }
John Reck915883b2017-05-03 10:27:20 -0700119 struct stat sb;
120 if (fstat(fd, &sb) || sb.st_size < sHeaderSize) {
121 int err = errno;
122 // The file not existing is normal for addToDump(), so only log if
123 // we get an unexpected error
124 if (err != ENOENT) {
125 ALOGW("Failed to fstat '%s', errno=%d (%s) (st_size %d)", path.c_str(), err,
John Reck1bcacfd2017-11-03 10:12:19 -0700126 strerror(err), (int)sb.st_size);
John Reck915883b2017-05-03 10:27:20 -0700127 }
128 return false;
129 }
130 void* addr = mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
zhangkuili24a1bc32018-05-29 10:23:29 +0800131 if (addr == MAP_FAILED) {
John Reck915883b2017-05-03 10:27:20 -0700132 int err = errno;
133 // The file not existing is normal for addToDump(), so only log if
134 // we get an unexpected error
135 if (err != ENOENT) {
136 ALOGW("Failed to mmap '%s', errno=%d (%s)", path.c_str(), err, strerror(err));
137 }
138 return false;
139 }
140 uint32_t file_version = *reinterpret_cast<uint32_t*>(addr);
141 if (file_version != sCurrentFileVersion) {
142 ALOGW("file_version mismatch! expected %d got %d", sCurrentFileVersion, file_version);
liulvping4832438c2018-12-20 20:34:56 +0800143 munmap(addr, sb.st_size);
John Reckdf1742e2017-01-19 15:56:21 -0800144 return false;
145 }
146
John Reck915883b2017-05-03 10:27:20 -0700147 void* data = reinterpret_cast<uint8_t*>(addr) + sHeaderSize;
148 int dataSize = sb.st_size - sHeaderSize;
149 io::ArrayInputStream input{data, dataSize};
John Reckdf1742e2017-01-19 15:56:21 -0800150 bool success = output->ParseFromZeroCopyStream(&input);
John Reck915883b2017-05-03 10:27:20 -0700151 if (!success) {
John Reck1bcacfd2017-11-03 10:12:19 -0700152 ALOGW("Parse failed on '%s' error='%s'", path.c_str(),
153 output->InitializationErrorString().c_str());
John Reckdf1742e2017-01-19 15:56:21 -0800154 }
liulvping4832438c2018-12-20 20:34:56 +0800155 munmap(addr, sb.st_size);
John Reckdf1742e2017-01-19 15:56:21 -0800156 return success;
157}
158
Kweku Adams1856a4c2018-04-03 16:31:10 -0700159bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto, const std::string& package,
Dianne Hackborn73453e42017-12-11 16:30:36 -0800160 int64_t versionCode, int64_t startTime, int64_t endTime,
John Reck1bcacfd2017-11-03 10:12:19 -0700161 const ProfileData* data) {
John Reckdf1742e2017-01-19 15:56:21 -0800162 if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
163 proto->set_stats_start(startTime);
164 }
165 if (proto->stats_end() == 0 || proto->stats_end() < endTime) {
166 proto->set_stats_end(endTime);
167 }
168 proto->set_package_name(package);
169 proto->set_version_code(versionCode);
170 auto summary = proto->mutable_summary();
John Reck7075c792017-07-05 14:03:43 -0700171 summary->set_total_frames(summary->total_frames() + data->totalFrameCount());
172 summary->set_janky_frames(summary->janky_frames() + data->jankFrameCount());
John Reck1bcacfd2017-11-03 10:12:19 -0700173 summary->set_missed_vsync_count(summary->missed_vsync_count() +
174 data->jankTypeCount(kMissedVsync));
175 summary->set_high_input_latency_count(summary->high_input_latency_count() +
176 data->jankTypeCount(kHighInputLatency));
177 summary->set_slow_ui_thread_count(summary->slow_ui_thread_count() +
178 data->jankTypeCount(kSlowUI));
179 summary->set_slow_bitmap_upload_count(summary->slow_bitmap_upload_count() +
180 data->jankTypeCount(kSlowSync));
181 summary->set_slow_draw_count(summary->slow_draw_count() + data->jankTypeCount(kSlowRT));
John Reck0e486472018-03-19 14:06:16 -0700182 summary->set_missed_deadline_count(summary->missed_deadline_count()
183 + data->jankTypeCount(kMissedDeadline));
John Reckdf1742e2017-01-19 15:56:21 -0800184
185 bool creatingHistogram = false;
186 if (proto->histogram_size() == 0) {
187 proto->mutable_histogram()->Reserve(sHistogramSize);
188 creatingHistogram = true;
189 } else if (proto->histogram_size() != sHistogramSize) {
John Reck1bcacfd2017-11-03 10:12:19 -0700190 ALOGE("Histogram size mismatch, proto is %d expected %d", proto->histogram_size(),
191 sHistogramSize);
John Reck5206a872017-09-18 11:08:31 -0700192 return false;
John Reckdf1742e2017-01-19 15:56:21 -0800193 }
John Reck7075c792017-07-05 14:03:43 -0700194 int index = 0;
John Reck5206a872017-09-18 11:08:31 -0700195 bool hitMergeError = false;
John Reck7075c792017-07-05 14:03:43 -0700196 data->histogramForEach([&](ProfileData::HistogramEntry entry) {
John Reck5206a872017-09-18 11:08:31 -0700197 if (hitMergeError) return;
198
Kweku Adams1856a4c2018-04-03 16:31:10 -0700199 protos::GraphicsStatsHistogramBucketProto* bucket;
John Reckdf1742e2017-01-19 15:56:21 -0800200 if (creatingHistogram) {
201 bucket = proto->add_histogram();
John Reck7075c792017-07-05 14:03:43 -0700202 bucket->set_render_millis(entry.renderTimeMs);
John Reckdf1742e2017-01-19 15:56:21 -0800203 } else {
John Reck7075c792017-07-05 14:03:43 -0700204 bucket = proto->mutable_histogram(index);
John Reck5206a872017-09-18 11:08:31 -0700205 if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
John Reck1bcacfd2017-11-03 10:12:19 -0700206 ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(),
207 entry.renderTimeMs);
John Reck5206a872017-09-18 11:08:31 -0700208 hitMergeError = true;
209 return;
210 }
John Reckdf1742e2017-01-19 15:56:21 -0800211 }
John Reck7075c792017-07-05 14:03:43 -0700212 bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
213 index++;
214 });
Stan Iliev7203e1f2019-07-25 13:12:02 -0400215 if (hitMergeError) return false;
216 // fill in GPU frame time histogram
217 creatingHistogram = false;
218 if (proto->gpu_histogram_size() == 0) {
219 proto->mutable_gpu_histogram()->Reserve(sGPUHistogramSize);
220 creatingHistogram = true;
221 } else if (proto->gpu_histogram_size() != sGPUHistogramSize) {
222 ALOGE("GPU histogram size mismatch, proto is %d expected %d", proto->gpu_histogram_size(),
223 sGPUHistogramSize);
224 return false;
225 }
226 index = 0;
227 data->histogramGPUForEach([&](ProfileData::HistogramEntry entry) {
228 if (hitMergeError) return;
229
230 protos::GraphicsStatsHistogramBucketProto* bucket;
231 if (creatingHistogram) {
232 bucket = proto->add_gpu_histogram();
233 bucket->set_render_millis(entry.renderTimeMs);
234 } else {
235 bucket = proto->mutable_gpu_histogram(index);
236 if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
237 ALOGW("GPU frame time mistmatch %d vs. %u", bucket->render_millis(),
238 entry.renderTimeMs);
239 hitMergeError = true;
240 return;
241 }
242 }
243 bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
244 index++;
245 });
John Reck5206a872017-09-18 11:08:31 -0700246 return !hitMergeError;
John Reckdf1742e2017-01-19 15:56:21 -0800247}
248
Kweku Adams1856a4c2018-04-03 16:31:10 -0700249static int32_t findPercentile(protos::GraphicsStatsProto* proto, int percentile) {
John Reckdf1742e2017-01-19 15:56:21 -0800250 int32_t pos = percentile * proto->summary().total_frames() / 100;
251 int32_t remaining = proto->summary().total_frames() - pos;
252 for (auto it = proto->histogram().rbegin(); it != proto->histogram().rend(); ++it) {
253 remaining -= it->frame_count();
254 if (remaining <= 0) {
255 return it->render_millis();
256 }
257 }
258 return 0;
259}
260
Stan Iliev7203e1f2019-07-25 13:12:02 -0400261static int32_t findGPUPercentile(protos::GraphicsStatsProto* proto, int percentile) {
262 uint32_t totalGPUFrameCount = 0; // this is usually proto->summary().total_frames() - 3.
263 for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) {
264 totalGPUFrameCount += it->frame_count();
265 }
266 int32_t pos = percentile * totalGPUFrameCount / 100;
267 int32_t remaining = totalGPUFrameCount - pos;
268 for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) {
269 remaining -= it->frame_count();
270 if (remaining <= 0) {
271 return it->render_millis();
272 }
273 }
274 return 0;
275}
276
Kweku Adams1856a4c2018-04-03 16:31:10 -0700277void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int fd) {
John Reckdf1742e2017-01-19 15:56:21 -0800278 // This isn't a full validation, just enough that we can deref at will
John Reck5206a872017-09-18 11:08:31 -0700279 if (proto->package_name().empty() || !proto->has_summary()) {
280 ALOGW("Skipping dump, invalid package_name() '%s' or summary %d",
John Reck1bcacfd2017-11-03 10:12:19 -0700281 proto->package_name().c_str(), proto->has_summary());
John Reck5206a872017-09-18 11:08:31 -0700282 return;
283 }
John Reckdf1742e2017-01-19 15:56:21 -0800284 dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
Colin Cross054b0c02018-11-04 17:24:17 -0800285 dprintf(fd, "\nVersion: %lld", proto->version_code());
286 dprintf(fd, "\nStats since: %lldns", proto->stats_start());
287 dprintf(fd, "\nStats end: %lldns", proto->stats_end());
John Reckdf1742e2017-01-19 15:56:21 -0800288 auto summary = proto->summary();
289 dprintf(fd, "\nTotal frames rendered: %d", summary.total_frames());
290 dprintf(fd, "\nJanky frames: %d (%.2f%%)", summary.janky_frames(),
John Reck1bcacfd2017-11-03 10:12:19 -0700291 (float)summary.janky_frames() / (float)summary.total_frames() * 100.0f);
John Reckdf1742e2017-01-19 15:56:21 -0800292 dprintf(fd, "\n50th percentile: %dms", findPercentile(proto, 50));
293 dprintf(fd, "\n90th percentile: %dms", findPercentile(proto, 90));
294 dprintf(fd, "\n95th percentile: %dms", findPercentile(proto, 95));
295 dprintf(fd, "\n99th percentile: %dms", findPercentile(proto, 99));
296 dprintf(fd, "\nNumber Missed Vsync: %d", summary.missed_vsync_count());
297 dprintf(fd, "\nNumber High input latency: %d", summary.high_input_latency_count());
298 dprintf(fd, "\nNumber Slow UI thread: %d", summary.slow_ui_thread_count());
299 dprintf(fd, "\nNumber Slow bitmap uploads: %d", summary.slow_bitmap_upload_count());
300 dprintf(fd, "\nNumber Slow issue draw commands: %d", summary.slow_draw_count());
John Reck0e486472018-03-19 14:06:16 -0700301 dprintf(fd, "\nNumber Frame deadline missed: %d", summary.missed_deadline_count());
John Reckdf1742e2017-01-19 15:56:21 -0800302 dprintf(fd, "\nHISTOGRAM:");
303 for (const auto& it : proto->histogram()) {
304 dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
305 }
Stan Iliev7203e1f2019-07-25 13:12:02 -0400306 dprintf(fd, "\n50th gpu percentile: %dms", findGPUPercentile(proto, 50));
307 dprintf(fd, "\n90th gpu percentile: %dms", findGPUPercentile(proto, 90));
308 dprintf(fd, "\n95th gpu percentile: %dms", findGPUPercentile(proto, 95));
309 dprintf(fd, "\n99th gpu percentile: %dms", findGPUPercentile(proto, 99));
310 dprintf(fd, "\nGPU HISTOGRAM:");
311 for (const auto& it : proto->gpu_histogram()) {
312 dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
313 }
John Reckdf1742e2017-01-19 15:56:21 -0800314 dprintf(fd, "\n");
315}
316
317void GraphicsStatsService::saveBuffer(const std::string& path, const std::string& package,
Dianne Hackborn73453e42017-12-11 16:30:36 -0800318 int64_t versionCode, int64_t startTime, int64_t endTime,
John Reck1bcacfd2017-11-03 10:12:19 -0700319 const ProfileData* data) {
Kweku Adams1856a4c2018-04-03 16:31:10 -0700320 protos::GraphicsStatsProto statsProto;
John Reckdf1742e2017-01-19 15:56:21 -0800321 if (!parseFromFile(path, &statsProto)) {
322 statsProto.Clear();
323 }
John Reck5206a872017-09-18 11:08:31 -0700324 if (!mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
325 return;
326 }
John Reckdf1742e2017-01-19 15:56:21 -0800327 // Although we might not have read any data from the file, merging the existing data
328 // should always fully-initialize the proto
John Reck5206a872017-09-18 11:08:31 -0700329 if (!statsProto.IsInitialized()) {
330 ALOGE("proto initialization error %s", statsProto.InitializationErrorString().c_str());
331 return;
332 }
333 if (statsProto.package_name().empty() || !statsProto.has_summary()) {
John Reck1bcacfd2017-11-03 10:12:19 -0700334 ALOGE("missing package_name() '%s' summary %d", statsProto.package_name().c_str(),
335 statsProto.has_summary());
John Reck5206a872017-09-18 11:08:31 -0700336 return;
337 }
John Reckdf1742e2017-01-19 15:56:21 -0800338 int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660);
339 if (outFd <= 0) {
340 int err = errno;
341 ALOGW("Failed to open '%s', error=%d (%s)", path.c_str(), err, strerror(err));
342 return;
343 }
344 int wrote = write(outFd, &sCurrentFileVersion, sHeaderSize);
345 if (wrote != sHeaderSize) {
346 int err = errno;
John Reck1bcacfd2017-11-03 10:12:19 -0700347 ALOGW("Failed to write header to '%s', returned=%d errno=%d (%s)", path.c_str(), wrote, err,
348 strerror(err));
John Reckdf1742e2017-01-19 15:56:21 -0800349 close(outFd);
350 return;
351 }
352 {
John Reck915883b2017-05-03 10:27:20 -0700353 FileOutputStreamLite output(outFd);
John Reckdf1742e2017-01-19 15:56:21 -0800354 bool success = statsProto.SerializeToZeroCopyStream(&output) && output.Flush();
355 if (output.GetErrno() != 0) {
John Reck1bcacfd2017-11-03 10:12:19 -0700356 ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)", outFd, path.c_str(),
357 output.GetErrno(), strerror(output.GetErrno()));
John Reckdf1742e2017-01-19 15:56:21 -0800358 success = false;
359 } else if (!success) {
360 ALOGW("Serialize failed on '%s' unknown error", path.c_str());
361 }
362 }
363 close(outFd);
364}
365
366class GraphicsStatsService::Dump {
367public:
368 Dump(int outFd, DumpType type) : mFd(outFd), mType(type) {}
369 int fd() { return mFd; }
370 DumpType type() { return mType; }
Kweku Adams1856a4c2018-04-03 16:31:10 -0700371 protos::GraphicsStatsServiceDumpProto& proto() { return mProto; }
John Reck1bcacfd2017-11-03 10:12:19 -0700372
John Reckdf1742e2017-01-19 15:56:21 -0800373private:
374 int mFd;
375 DumpType mType;
Kweku Adams1856a4c2018-04-03 16:31:10 -0700376 protos::GraphicsStatsServiceDumpProto mProto;
John Reckdf1742e2017-01-19 15:56:21 -0800377};
378
379GraphicsStatsService::Dump* GraphicsStatsService::createDump(int outFd, DumpType type) {
380 return new Dump(outFd, type);
381}
382
John Reck1bcacfd2017-11-03 10:12:19 -0700383void GraphicsStatsService::addToDump(Dump* dump, const std::string& path,
Dianne Hackborn73453e42017-12-11 16:30:36 -0800384 const std::string& package, int64_t versionCode,
385 int64_t startTime, int64_t endTime, const ProfileData* data) {
Kweku Adams1856a4c2018-04-03 16:31:10 -0700386 protos::GraphicsStatsProto statsProto;
John Reckdf1742e2017-01-19 15:56:21 -0800387 if (!path.empty() && !parseFromFile(path, &statsProto)) {
388 statsProto.Clear();
389 }
John Reck1bcacfd2017-11-03 10:12:19 -0700390 if (data &&
391 !mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
John Reck5206a872017-09-18 11:08:31 -0700392 return;
John Reckdf1742e2017-01-19 15:56:21 -0800393 }
394 if (!statsProto.IsInitialized()) {
395 ALOGW("Failed to load profile data from path '%s' and data %p",
John Reck1bcacfd2017-11-03 10:12:19 -0700396 path.empty() ? "<empty>" : path.c_str(), data);
John Reckdf1742e2017-01-19 15:56:21 -0800397 return;
398 }
399
400 if (dump->type() == DumpType::Protobuf) {
401 dump->proto().add_stats()->CopyFrom(statsProto);
402 } else {
403 dumpAsTextToFd(&statsProto, dump->fd());
404 }
405}
406
407void GraphicsStatsService::addToDump(Dump* dump, const std::string& path) {
Kweku Adams1856a4c2018-04-03 16:31:10 -0700408 protos::GraphicsStatsProto statsProto;
John Reckdf1742e2017-01-19 15:56:21 -0800409 if (!parseFromFile(path, &statsProto)) {
410 return;
411 }
412 if (dump->type() == DumpType::Protobuf) {
413 dump->proto().add_stats()->CopyFrom(statsProto);
414 } else {
415 dumpAsTextToFd(&statsProto, dump->fd());
416 }
417}
418
419void GraphicsStatsService::finishDump(Dump* dump) {
420 if (dump->type() == DumpType::Protobuf) {
John Reck915883b2017-05-03 10:27:20 -0700421 FileOutputStreamLite stream(dump->fd());
John Reckdf1742e2017-01-19 15:56:21 -0800422 dump->proto().SerializeToZeroCopyStream(&stream);
423 }
424 delete dump;
425}
426
427} /* namespace uirenderer */
Dan Albert110e0072017-10-11 12:41:26 -0700428} /* namespace android */