• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 #define LOG_TAG "SurfaceFlingerPuller"
18 
19 #include "SurfaceFlingerPuller.h"
20 
21 #include <gui/SurfaceComposerClient.h>
22 #include <log/log.h>
23 #include <statslog.h>
24 #include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
25 
26 #include <vector>
27 
28 namespace android {
29 namespace server {
30 namespace stats {
31 
32 using android::util::BytesField;
33 using std::optional;
34 
35 namespace {
getBytes(const google::protobuf::MessageLite & proto,std::string & data)36 optional<BytesField> getBytes(const google::protobuf::MessageLite& proto, std::string& data) {
37     if (!proto.SerializeToString(&data)) {
38         ALOGW("Unable to serialize surface flinger bytes field");
39         return std::nullopt;
40     }
41     return {BytesField(data.data(), data.size())};
42 }
43 } // namespace
44 
pull(int32_t atomTag,AStatsEventList * data)45 AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::pull(int32_t atomTag,
46                                                                 AStatsEventList* data) {
47     // Don't need mutexes here, since there is no global state.
48     // SurfaceComposerClient is thread safe, and surfaceflinger is internally thread safe.
49 
50     bool success = false;
51     std::string pullDataProto;
52     status_t err = SurfaceComposerClient::onPullAtom(atomTag, &pullDataProto, &success);
53     if (!success || err != NO_ERROR) {
54         ALOGW("Failed to pull atom %" PRId32
55               " from surfaceflinger. Success is %d, binder status is %s",
56               atomTag, (int)success, binder::Status::exceptionToString(err).c_str());
57         return AStatsManager_PULL_SKIP;
58     }
59 
60     switch (atomTag) {
61         case android::util::SURFACEFLINGER_STATS_GLOBAL_INFO:
62             return parseGlobalInfoPull(pullDataProto, data);
63         case android::util::SURFACEFLINGER_STATS_LAYER_INFO:
64             return parseLayerInfoPull(pullDataProto, data);
65         default:
66             ALOGW("Invalid atom id for surfaceflinger pullers: %" PRId32, atomTag);
67             return AStatsManager_PULL_SKIP;
68     }
69 }
70 
parseGlobalInfoPull(const std::string & protoData,AStatsEventList * data)71 AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::parseGlobalInfoPull(
72         const std::string& protoData, AStatsEventList* data) {
73     android::surfaceflinger::SurfaceflingerStatsGlobalInfoWrapper atomList;
74     if (!atomList.ParseFromString(protoData)) {
75         ALOGW("Error parsing surface flinger global stats to proto");
76         return AStatsManager_PULL_SKIP;
77     }
78 
79     for (const auto& atom : atomList.atom()) {
80         // The strings must outlive the BytesFields, which only have a pointer to the data.
81         std::string frameDurationStr, renderEngineTimeStr, deadlineMissesStr, predictionErrorsStr;
82         optional<BytesField> frameDuration = getBytes(atom.frame_duration(), frameDurationStr);
83         optional<BytesField> renderEngineTime =
84                 getBytes(atom.render_engine_timing(), renderEngineTimeStr);
85         optional<BytesField> deadlineMisses =
86                 getBytes(atom.sf_deadline_misses(), deadlineMissesStr);
87         optional<BytesField> predictionErrors =
88                 getBytes(atom.sf_prediction_errors(), predictionErrorsStr);
89 
90         // Fail if any serialization to bytes failed.
91         if (!frameDuration || !renderEngineTime || !deadlineMisses || !predictionErrors) {
92             return AStatsManager_PULL_SKIP;
93         }
94 
95         android::util::addAStatsEvent(data, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
96                                       atom.total_frames(), atom.missed_frames(),
97                                       atom.client_composition_frames(), atom.display_on_millis(),
98                                       atom.animation_millis(), atom.event_connection_count(),
99                                       frameDuration.value(), renderEngineTime.value(),
100                                       atom.total_timeline_frames(), atom.total_janky_frames(),
101                                       atom.total_janky_frames_with_long_cpu(),
102                                       atom.total_janky_frames_with_long_gpu(),
103                                       atom.total_janky_frames_sf_unattributed(),
104                                       atom.total_janky_frames_app_unattributed(),
105                                       atom.total_janky_frames_sf_scheduling(),
106                                       atom.total_jank_frames_sf_prediction_error(),
107                                       atom.total_jank_frames_app_buffer_stuffing(),
108                                       atom.display_refresh_rate_bucket(), deadlineMisses.value(),
109                                       predictionErrors.value(), atom.render_rate_bucket());
110     }
111     return AStatsManager_PULL_SUCCESS;
112 }
113 
parseLayerInfoPull(const std::string & protoData,AStatsEventList * data)114 AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::parseLayerInfoPull(
115         const std::string& protoData, AStatsEventList* data) {
116     android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
117     if (!atomList.ParseFromString(protoData)) {
118         ALOGW("Error parsing surface flinger layer stats to proto");
119         return AStatsManager_PULL_SKIP;
120     }
121 
122     for (const auto& atom : atomList.atom()) {
123         // The strings must outlive the BytesFields, which only have a pointer to the data.
124         std::string present2PresentStr, post2presentStr, acquire2PresentStr, latch2PresentStr,
125                 desired2PresentStr, post2AcquireStr, frameRateVoteStr, appDeadlineMissesStr;
126         optional<BytesField> present2Present =
127                 getBytes(atom.present_to_present(), present2PresentStr);
128         optional<BytesField> post2present = getBytes(atom.post_to_present(), post2presentStr);
129         optional<BytesField> acquire2Present =
130                 getBytes(atom.acquire_to_present(), acquire2PresentStr);
131         optional<BytesField> latch2Present = getBytes(atom.latch_to_present(), latch2PresentStr);
132         optional<BytesField> desired2Present =
133                 getBytes(atom.desired_to_present(), desired2PresentStr);
134         optional<BytesField> post2Acquire = getBytes(atom.post_to_acquire(), post2AcquireStr);
135         optional<BytesField> frameRateVote = getBytes(atom.set_frame_rate_vote(), frameRateVoteStr);
136         optional<BytesField> appDeadlineMisses =
137                 getBytes(atom.app_deadline_misses(), appDeadlineMissesStr);
138 
139         // Fail if any serialization to bytes failed.
140         if (!present2Present || !post2present || !acquire2Present || !latch2Present ||
141             !desired2Present || !post2Acquire || !frameRateVote || !appDeadlineMisses) {
142             return AStatsManager_PULL_SKIP;
143         }
144 
145         android::util::addAStatsEvent(data, android::util::SURFACEFLINGER_STATS_LAYER_INFO,
146                                       atom.layer_name().c_str(), atom.total_frames(),
147                                       atom.dropped_frames(), present2Present.value(),
148                                       post2present.value(), acquire2Present.value(),
149                                       latch2Present.value(), desired2Present.value(),
150                                       post2Acquire.value(), atom.late_acquire_frames(),
151                                       atom.bad_desired_present_frames(), atom.uid(),
152                                       atom.total_timeline_frames(), atom.total_janky_frames(),
153                                       atom.total_janky_frames_with_long_cpu(),
154                                       atom.total_janky_frames_with_long_gpu(),
155                                       atom.total_janky_frames_sf_unattributed(),
156                                       atom.total_janky_frames_app_unattributed(),
157                                       atom.total_janky_frames_sf_scheduling(),
158                                       atom.total_jank_frames_sf_prediction_error(),
159                                       atom.total_jank_frames_app_buffer_stuffing(),
160                                       atom.display_refresh_rate_bucket(), atom.render_rate_bucket(),
161                                       frameRateVote.value(), appDeadlineMisses.value(),
162                                       atom.game_mode());
163     }
164     return AStatsManager_PULL_SUCCESS;
165 }
166 
167 } // namespace stats
168 } // namespace server
169 } // namespace android
170