1 /*
2  * Copyright 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 #undef LOG_TAG
17 #define LOG_TAG "SurfaceTracing"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 
20 #include "SurfaceTracing.h"
21 #include <SurfaceFlinger.h>
22 
23 #include <android-base/file.h>
24 #include <android-base/stringprintf.h>
25 #include <log/log.h>
26 #include <utils/SystemClock.h>
27 #include <utils/Trace.h>
28 
29 namespace android {
30 
SurfaceTracing(SurfaceFlinger & flinger)31 SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
32       : mFlinger(flinger), mSfLock(flinger.mDrawingStateLock) {}
33 
mainLoop()34 void SurfaceTracing::mainLoop() {
35     addFirstEntry();
36     bool enabled = true;
37     while (enabled) {
38         LayersTraceProto entry = traceWhenNotified();
39         enabled = addTraceToBuffer(entry);
40     }
41 }
42 
addFirstEntry()43 void SurfaceTracing::addFirstEntry() {
44     LayersTraceProto entry;
45     {
46         std::scoped_lock lock(mSfLock);
47         entry = traceLayersLocked("tracing.enable");
48     }
49     addTraceToBuffer(entry);
50 }
51 
traceWhenNotified()52 LayersTraceProto SurfaceTracing::traceWhenNotified() {
53     std::unique_lock<std::mutex> lock(mSfLock);
54     mCanStartTrace.wait(lock);
55     android::base::ScopedLockAssertion assumeLock(mSfLock);
56     LayersTraceProto entry = traceLayersLocked(mWhere);
57     lock.unlock();
58     return entry;
59 }
60 
addTraceToBuffer(LayersTraceProto & entry)61 bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
62     std::scoped_lock lock(mTraceLock);
63     mBuffer.emplace(std::move(entry));
64     if (mWriteToFile) {
65         writeProtoFileLocked();
66         mWriteToFile = false;
67     }
68     return mEnabled;
69 }
70 
notify(long compositionTime,const char * where)71 void SurfaceTracing::notify(long compositionTime, const char* where) {
72     std::scoped_lock lock(mSfLock);
73     mCompositionTime = compositionTime;
74     mWhere = where;
75     mCanStartTrace.notify_one();
76 }
77 
writeToFileAsync()78 void SurfaceTracing::writeToFileAsync() {
79     std::scoped_lock lock(mTraceLock);
80     mWriteToFile = true;
81     mCanStartTrace.notify_one();
82 }
83 
reset(size_t newSize)84 void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
85     // use the swap trick to make sure memory is released
86     std::queue<LayersTraceProto>().swap(mStorage);
87     mSizeInBytes = newSize;
88     mUsedInBytes = 0U;
89 }
90 
emplace(LayersTraceProto && proto)91 void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
92     auto protoSize = proto.ByteSize();
93     while (mUsedInBytes + protoSize > mSizeInBytes) {
94         if (mStorage.empty()) {
95             return;
96         }
97         mUsedInBytes -= mStorage.front().ByteSize();
98         mStorage.pop();
99     }
100     mUsedInBytes += protoSize;
101     mStorage.emplace();
102     mStorage.back().Swap(&proto);
103 }
104 
flush(LayersTraceFileProto * fileProto)105 void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
106     fileProto->mutable_entry()->Reserve(mStorage.size());
107 
108     while (!mStorage.empty()) {
109         auto entry = fileProto->add_entry();
110         entry->Swap(&mStorage.front());
111         mStorage.pop();
112     }
113 }
114 
enable()115 void SurfaceTracing::enable() {
116     std::scoped_lock lock(mTraceLock);
117 
118     if (mEnabled) {
119         return;
120     }
121     mBuffer.reset(mBufferSize);
122     mEnabled = true;
123     mThread = std::thread(&SurfaceTracing::mainLoop, this);
124 }
125 
writeToFile()126 status_t SurfaceTracing::writeToFile() {
127     mThread.join();
128     return mLastErr;
129 }
130 
disable()131 bool SurfaceTracing::disable() {
132     std::scoped_lock lock(mTraceLock);
133 
134     if (!mEnabled) {
135         return false;
136     }
137 
138     mEnabled = false;
139     mWriteToFile = true;
140     mCanStartTrace.notify_all();
141     return true;
142 }
143 
isEnabled() const144 bool SurfaceTracing::isEnabled() const {
145     std::scoped_lock lock(mTraceLock);
146     return mEnabled;
147 }
148 
setBufferSize(size_t bufferSizeInByte)149 void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
150     std::scoped_lock lock(mTraceLock);
151     mBufferSize = bufferSizeInByte;
152     mBuffer.setSize(bufferSizeInByte);
153 }
154 
setTraceFlags(uint32_t flags)155 void SurfaceTracing::setTraceFlags(uint32_t flags) {
156     std::scoped_lock lock(mSfLock);
157     mTraceFlags = flags;
158 }
159 
traceLayersLocked(const char * where)160 LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
161     ATRACE_CALL();
162 
163     LayersTraceProto entry;
164     entry.set_elapsed_realtime_nanos(mCompositionTime);
165     entry.set_where(where);
166     LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
167     entry.mutable_layers()->Swap(&layers);
168 
169     return entry;
170 }
171 
writeProtoFileLocked()172 void SurfaceTracing::writeProtoFileLocked() {
173     ATRACE_CALL();
174 
175     LayersTraceFileProto fileProto;
176     std::string output;
177 
178     fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
179                                LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
180     mBuffer.flush(&fileProto);
181     mBuffer.reset(mBufferSize);
182 
183     if (!fileProto.SerializeToString(&output)) {
184         ALOGE("Could not save the proto file! Permission denied");
185         mLastErr = PERMISSION_DENIED;
186     }
187     if (!android::base::WriteStringToFile(output, kDefaultFileName, S_IRWXU | S_IRGRP, getuid(),
188                                           getgid(), true)) {
189         ALOGE("Could not save the proto file! There are missing fields");
190         mLastErr = PERMISSION_DENIED;
191     }
192 
193     mLastErr = NO_ERROR;
194 }
195 
dump(std::string & result) const196 void SurfaceTracing::dump(std::string& result) const {
197     std::scoped_lock lock(mTraceLock);
198     base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
199     base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
200                         mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
201                         float(mBuffer.size()) / float(1_MB));
202 }
203 
204 } // namespace android
205