• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(const char * where)71 void SurfaceTracing::notify(const char* where) {
72     std::scoped_lock lock(mSfLock);
73     mWhere = where;
74     mCanStartTrace.notify_one();
75 }
76 
writeToFileAsync()77 void SurfaceTracing::writeToFileAsync() {
78     std::scoped_lock lock(mTraceLock);
79     mWriteToFile = true;
80     mCanStartTrace.notify_one();
81 }
82 
reset(size_t newSize)83 void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
84     // use the swap trick to make sure memory is released
85     std::queue<LayersTraceProto>().swap(mStorage);
86     mSizeInBytes = newSize;
87     mUsedInBytes = 0U;
88 }
89 
emplace(LayersTraceProto && proto)90 void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
91     auto protoSize = proto.ByteSize();
92     while (mUsedInBytes + protoSize > mSizeInBytes) {
93         if (mStorage.empty()) {
94             return;
95         }
96         mUsedInBytes -= mStorage.front().ByteSize();
97         mStorage.pop();
98     }
99     mUsedInBytes += protoSize;
100     mStorage.emplace();
101     mStorage.back().Swap(&proto);
102 }
103 
flush(LayersTraceFileProto * fileProto)104 void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
105     fileProto->mutable_entry()->Reserve(mStorage.size());
106 
107     while (!mStorage.empty()) {
108         auto entry = fileProto->add_entry();
109         entry->Swap(&mStorage.front());
110         mStorage.pop();
111     }
112 }
113 
enable()114 void SurfaceTracing::enable() {
115     std::scoped_lock lock(mTraceLock);
116 
117     if (mEnabled) {
118         return;
119     }
120     mBuffer.reset(mBufferSize);
121     mEnabled = true;
122     mThread = std::thread(&SurfaceTracing::mainLoop, this);
123 }
124 
writeToFile()125 status_t SurfaceTracing::writeToFile() {
126     mThread.join();
127     return mLastErr;
128 }
129 
disable()130 bool SurfaceTracing::disable() {
131     std::scoped_lock lock(mTraceLock);
132 
133     if (!mEnabled) {
134         return false;
135     }
136 
137     mEnabled = false;
138     mWriteToFile = true;
139     mCanStartTrace.notify_all();
140     return true;
141 }
142 
isEnabled() const143 bool SurfaceTracing::isEnabled() const {
144     std::scoped_lock lock(mTraceLock);
145     return mEnabled;
146 }
147 
setBufferSize(size_t bufferSizeInByte)148 void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
149     std::scoped_lock lock(mTraceLock);
150     mBufferSize = bufferSizeInByte;
151     mBuffer.setSize(bufferSizeInByte);
152 }
153 
setTraceFlags(uint32_t flags)154 void SurfaceTracing::setTraceFlags(uint32_t flags) {
155     std::scoped_lock lock(mSfLock);
156     mTraceFlags = flags;
157 }
158 
traceLayersLocked(const char * where)159 LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
160     ATRACE_CALL();
161 
162     LayersTraceProto entry;
163     entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
164     entry.set_where(where);
165     LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags));
166     entry.mutable_layers()->Swap(&layers);
167 
168     return entry;
169 }
170 
writeProtoFileLocked()171 void SurfaceTracing::writeProtoFileLocked() {
172     ATRACE_CALL();
173 
174     LayersTraceFileProto fileProto;
175     std::string output;
176 
177     fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
178                                LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
179     mBuffer.flush(&fileProto);
180     mBuffer.reset(mBufferSize);
181 
182     if (!fileProto.SerializeToString(&output)) {
183         ALOGE("Could not save the proto file! Permission denied");
184         mLastErr = PERMISSION_DENIED;
185     }
186     if (!android::base::WriteStringToFile(output, kDefaultFileName, S_IRWXU | S_IRGRP, getuid(),
187                                           getgid(), true)) {
188         ALOGE("Could not save the proto file! There are missing fields");
189         mLastErr = PERMISSION_DENIED;
190     }
191 
192     mLastErr = NO_ERROR;
193 }
194 
dump(std::string & result) const195 void SurfaceTracing::dump(std::string& result) const {
196     std::scoped_lock lock(mTraceLock);
197     base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
198     base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
199                         mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
200                         float(mBuffer.size()) / float(1_MB));
201 }
202 
203 } // namespace android
204