1df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck/*
2df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * Copyright (C) 2017 The Android Open Source Project
3df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck *
4df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * Licensed under the Apache License, Version 2.0 (the "License");
5df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * you may not use this file except in compliance with the License.
6df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * You may obtain a copy of the License at
7df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck *
8df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck *      http://www.apache.org/licenses/LICENSE-2.0
9df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck *
10df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * Unless required by applicable law or agreed to in writing, software
11df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * distributed under the License is distributed on an "AS IS" BASIS,
12df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * See the License for the specific language governing permissions and
14df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * limitations under the License.
15df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck */
16df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
17df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include "GraphicsStatsService.h"
18df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
19df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include "JankTracker.h"
20df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
21df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <frameworks/base/core/proto/android/service/graphicsstats.pb.h>
22df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <google/protobuf/io/zero_copy_stream_impl.h>
23df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <log/log.h>
24df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
25df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <inttypes.h>
26df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <sys/types.h>
27df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <sys/stat.h>
28df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <fcntl.h>
29df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <unistd.h>
30df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
31df1742ed47da1e9b61afeae16fa448d5302a8aa0John Recknamespace android {
32df1742ed47da1e9b61afeae16fa448d5302a8aa0John Recknamespace uirenderer {
33df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
34df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckusing namespace google::protobuf;
35df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
36df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckconstexpr int32_t sCurrentFileVersion = 1;
37df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckconstexpr int32_t sHeaderSize = 4;
38df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong");
39df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
40df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckconstexpr int sHistogramSize =
41df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        std::tuple_size<decltype(ProfileData::frameCounts)>::value +
42df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        std::tuple_size<decltype(ProfileData::slowFrameCounts)>::value;
43df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
44df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
45df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        const std::string& package, int versionCode, int64_t startTime, int64_t endTime,
46df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        const ProfileData* data);
47df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
48df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
49df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckbool GraphicsStatsService::parseFromFile(const std::string& path, service::GraphicsStatsProto* output) {
50df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
51df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    int fd = open(path.c_str(), O_RDONLY);
52df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (fd == -1) {
53df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int err = errno;
54df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        // The file not existing is normal for addToDump(), so only log if
55df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        // we get an unexpected error
56df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        if (err != ENOENT) {
57df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            ALOGW("Failed to open '%s', errno=%d (%s)", path.c_str(), err, strerror(err));
58df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        }
59df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        return false;
60df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
61df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    uint32_t file_version;
62df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    ssize_t bytesRead = read(fd, &file_version, sHeaderSize);
63df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (bytesRead != sHeaderSize || file_version != sCurrentFileVersion) {
64df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        ALOGW("Failed to read '%s', bytesRead=%zd file_version=%d", path.c_str(), bytesRead,
65df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                file_version);
66df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        close(fd);
67df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        return false;
68df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
69df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
70df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    io::FileInputStream input(fd);
71df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    bool success = output->ParseFromZeroCopyStream(&input);
72df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (input.GetErrno() != 0) {
73df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        ALOGW("Error reading from fd=%d, path='%s' err=%d (%s)",
74df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                fd, path.c_str(), input.GetErrno(), strerror(input.GetErrno()));
75df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        success = false;
76df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    } else if (!success) {
77df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        ALOGW("Parse failed on '%s' error='%s'",
78df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                path.c_str(), output->InitializationErrorString().c_str());
79df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
80df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    close(fd);
81df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    return success;
82df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
83df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
84df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
85df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
86df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
87df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        proto->set_stats_start(startTime);
88df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
89df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (proto->stats_end() == 0 || proto->stats_end() < endTime) {
90df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        proto->set_stats_end(endTime);
91df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
92df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    proto->set_package_name(package);
93df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    proto->set_version_code(versionCode);
94df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    auto summary = proto->mutable_summary();
95df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    summary->set_total_frames(summary->total_frames() + data->totalFrameCount);
96df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    summary->set_janky_frames(summary->janky_frames() + data->jankFrameCount);
97df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    summary->set_missed_vsync_count(
98df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            summary->missed_vsync_count() + data->jankTypeCounts[kMissedVsync]);
99df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    summary->set_high_input_latency_count(
100df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            summary->high_input_latency_count() + data->jankTypeCounts[kHighInputLatency]);
101df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    summary->set_slow_ui_thread_count(
102df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            summary->slow_ui_thread_count() + data->jankTypeCounts[kSlowUI]);
103df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    summary->set_slow_bitmap_upload_count(
104df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            summary->slow_bitmap_upload_count() + data->jankTypeCounts[kSlowSync]);
105df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    summary->set_slow_draw_count(
106df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            summary->slow_draw_count() + data->jankTypeCounts[kSlowRT]);
107df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
108df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    bool creatingHistogram = false;
109df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (proto->histogram_size() == 0) {
110df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        proto->mutable_histogram()->Reserve(sHistogramSize);
111df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        creatingHistogram = true;
112df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    } else if (proto->histogram_size() != sHistogramSize) {
113df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        LOG_ALWAYS_FATAL("Histogram size mismatch, proto is %d expected %d",
114df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                proto->histogram_size(), sHistogramSize);
115df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
116df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    for (size_t i = 0; i < data->frameCounts.size(); i++) {
117df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        service::GraphicsStatsHistogramBucketProto* bucket;
118df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int32_t renderTime = JankTracker::frameTimeForFrameCountIndex(i);
119df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        if (creatingHistogram) {
120df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            bucket = proto->add_histogram();
121df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            bucket->set_render_millis(renderTime);
122df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        } else {
123df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            bucket = proto->mutable_histogram(i);
124df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            LOG_ALWAYS_FATAL_IF(bucket->render_millis() != renderTime,
125df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                    "Frame time mistmatch %d vs. %d", bucket->render_millis(), renderTime);
126df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        }
127df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        bucket->set_frame_count(bucket->frame_count() + data->frameCounts[i]);
128df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
129df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    for (size_t i = 0; i < data->slowFrameCounts.size(); i++) {
130df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        service::GraphicsStatsHistogramBucketProto* bucket;
131df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int32_t renderTime = JankTracker::frameTimeForSlowFrameCountIndex(i);
132df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        if (creatingHistogram) {
133df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            bucket = proto->add_histogram();
134df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            bucket->set_render_millis(renderTime);
135df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        } else {
136df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            constexpr int offset = std::tuple_size<decltype(ProfileData::frameCounts)>::value;
137df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            bucket = proto->mutable_histogram(offset + i);
138df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            LOG_ALWAYS_FATAL_IF(bucket->render_millis() != renderTime,
139df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                    "Frame time mistmatch %d vs. %d", bucket->render_millis(), renderTime);
140df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        }
141df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        bucket->set_frame_count(bucket->frame_count() + data->slowFrameCounts[i]);
142df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
143df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
144df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
145df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic int32_t findPercentile(service::GraphicsStatsProto* proto, int percentile) {
146df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    int32_t pos = percentile * proto->summary().total_frames() / 100;
147df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    int32_t remaining = proto->summary().total_frames() - pos;
148df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    for (auto it = proto->histogram().rbegin(); it != proto->histogram().rend(); ++it) {
149df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        remaining -= it->frame_count();
150df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        if (remaining <= 0) {
151df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            return it->render_millis();
152df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        }
153df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
154df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    return 0;
155df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
156df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
157df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) {
158df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    // This isn't a full validation, just enough that we can deref at will
159df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    LOG_ALWAYS_FATAL_IF(proto->package_name().empty()
160df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            || !proto->has_summary(), "package_name() '%s' summary %d",
161df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            proto->package_name().c_str(), proto->has_summary());
162df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
163df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nVersion: %d", proto->version_code());
164df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nStats since: %lldns", proto->stats_start());
165df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nStats end: %lldns", proto->stats_end());
166df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    auto summary = proto->summary();
167df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nTotal frames rendered: %d", summary.total_frames());
168df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nJanky frames: %d (%.2f%%)", summary.janky_frames(),
169df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            (float) summary.janky_frames() / (float) summary.total_frames() * 100.0f);
170df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\n50th percentile: %dms", findPercentile(proto, 50));
171df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\n90th percentile: %dms", findPercentile(proto, 90));
172df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\n95th percentile: %dms", findPercentile(proto, 95));
173df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\n99th percentile: %dms", findPercentile(proto, 99));
174df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nNumber Missed Vsync: %d", summary.missed_vsync_count());
175df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nNumber High input latency: %d", summary.high_input_latency_count());
176df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nNumber Slow UI thread: %d", summary.slow_ui_thread_count());
177df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nNumber Slow bitmap uploads: %d", summary.slow_bitmap_upload_count());
178df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nNumber Slow issue draw commands: %d", summary.slow_draw_count());
179df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\nHISTOGRAM:");
180df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    for (const auto& it : proto->histogram()) {
181df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
182df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
183df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    dprintf(fd, "\n");
184df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
185df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
186df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::saveBuffer(const std::string& path, const std::string& package,
187df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
188df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    service::GraphicsStatsProto statsProto;
189df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (!parseFromFile(path, &statsProto)) {
190df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        statsProto.Clear();
191df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
192df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
193df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    // Although we might not have read any data from the file, merging the existing data
194df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    // should always fully-initialize the proto
195df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    LOG_ALWAYS_FATAL_IF(!statsProto.IsInitialized(), "%s",
196df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            statsProto.InitializationErrorString().c_str());
197df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    LOG_ALWAYS_FATAL_IF(statsProto.package_name().empty()
198df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            || !statsProto.has_summary(), "package_name() '%s' summary %d",
199df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            statsProto.package_name().c_str(), statsProto.has_summary());
200df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660);
201df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (outFd <= 0) {
202df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int err = errno;
203df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        ALOGW("Failed to open '%s', error=%d (%s)", path.c_str(), err, strerror(err));
204df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        return;
205df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
206df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    int wrote = write(outFd, &sCurrentFileVersion, sHeaderSize);
207df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (wrote != sHeaderSize) {
208df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int err = errno;
209df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        ALOGW("Failed to write header to '%s', returned=%d errno=%d (%s)",
210df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                path.c_str(), wrote, err, strerror(err));
211df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        close(outFd);
212df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        return;
213df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
214df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    {
215df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        io::FileOutputStream output(outFd);
216df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        bool success = statsProto.SerializeToZeroCopyStream(&output) && output.Flush();
217df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        if (output.GetErrno() != 0) {
218df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)",
219df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                    outFd, path.c_str(), output.GetErrno(), strerror(output.GetErrno()));
220df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            success = false;
221df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        } else if (!success) {
222df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck            ALOGW("Serialize failed on '%s' unknown error", path.c_str());
223df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        }
224df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
225df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    close(outFd);
226df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
227df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
228df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckclass GraphicsStatsService::Dump {
229df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckpublic:
230df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    Dump(int outFd, DumpType type) : mFd(outFd), mType(type) {}
231df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    int fd() { return mFd; }
232df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    DumpType type() { return mType; }
233df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    service::GraphicsStatsServiceDumpProto& proto() { return mProto; }
234df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckprivate:
235df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    int mFd;
236df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    DumpType mType;
237df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    service::GraphicsStatsServiceDumpProto mProto;
238df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck};
239df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
240df1742ed47da1e9b61afeae16fa448d5302a8aa0John ReckGraphicsStatsService::Dump* GraphicsStatsService::createDump(int outFd, DumpType type) {
241df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    return new Dump(outFd, type);
242df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
243df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
244df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::addToDump(Dump* dump, const std::string& path, const std::string& package,
245df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
246df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    service::GraphicsStatsProto statsProto;
247df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (!path.empty() && !parseFromFile(path, &statsProto)) {
248df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        statsProto.Clear();
249df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
250df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (data) {
251df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
252df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
253df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (!statsProto.IsInitialized()) {
254df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        ALOGW("Failed to load profile data from path '%s' and data %p",
255df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck                path.empty() ? "<empty>" : path.c_str(), data);
256df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        return;
257df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
258df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
259df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (dump->type() == DumpType::Protobuf) {
260df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        dump->proto().add_stats()->CopyFrom(statsProto);
261df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    } else {
262df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        dumpAsTextToFd(&statsProto, dump->fd());
263df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
264df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
265df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
266df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::addToDump(Dump* dump, const std::string& path) {
267df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    service::GraphicsStatsProto statsProto;
268df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (!parseFromFile(path, &statsProto)) {
269df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        return;
270df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
271df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (dump->type() == DumpType::Protobuf) {
272df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        dump->proto().add_stats()->CopyFrom(statsProto);
273df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    } else {
274df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        dumpAsTextToFd(&statsProto, dump->fd());
275df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
276df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
277df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
278df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::finishDump(Dump* dump) {
279df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    if (dump->type() == DumpType::Protobuf) {
280df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        io::FileOutputStream stream(dump->fd());
281df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck        dump->proto().SerializeToZeroCopyStream(&stream);
282df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    }
283df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck    delete dump;
284df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}
285df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck
286df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} /* namespace uirenderer */
287df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} /* namespace android */