| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 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 | */ | 
| Ady Abraham | b0dbdaa | 2020-01-06 16:19:42 -0800 | [diff] [blame] | 16 |  | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 17 | #undef LOG_TAG | 
|  | 18 | #define LOG_TAG "SurfaceTracing" | 
|  | 19 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 
|  | 20 |  | 
|  | 21 | #include "SurfaceTracing.h" | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 22 | #include <SurfaceFlinger.h> | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 23 |  | 
|  | 24 | #include <android-base/file.h> | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 25 | #include <android-base/stringprintf.h> | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 26 | #include <log/log.h> | 
|  | 27 | #include <utils/SystemClock.h> | 
|  | 28 | #include <utils/Trace.h> | 
|  | 29 |  | 
|  | 30 | namespace android { | 
|  | 31 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 32 | SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {} | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 33 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 34 | bool SurfaceTracing::enable() { | 
| Vishnu Nair | 9245d3b | 2019-03-22 13:38:56 -0700 | [diff] [blame] | 35 | std::scoped_lock lock(mTraceLock); | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 36 | if (mEnabled) { | 
|  | 37 | return false; | 
| Vishnu Nair | 9245d3b | 2019-03-22 13:38:56 -0700 | [diff] [blame] | 38 | } | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 39 |  | 
|  | 40 | if (flagIsSet(TRACE_SYNC)) { | 
|  | 41 | runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig); | 
|  | 42 | } else { | 
|  | 43 | runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig, | 
|  | 44 | mFlinger.mTracingLock); | 
|  | 45 | } | 
|  | 46 | mEnabled = true; | 
|  | 47 | return true; | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | bool SurfaceTracing::disable() { | 
|  | 51 | std::scoped_lock lock(mTraceLock); | 
|  | 52 | if (!mEnabled) { | 
|  | 53 | return false; | 
|  | 54 | } | 
|  | 55 | mEnabled = false; | 
|  | 56 | runner->stop(); | 
|  | 57 | return true; | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | bool SurfaceTracing::isEnabled() const { | 
|  | 61 | std::scoped_lock lock(mTraceLock); | 
| Vishnu Nair | 9245d3b | 2019-03-22 13:38:56 -0700 | [diff] [blame] | 62 | return mEnabled; | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 63 | } | 
|  | 64 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 65 | status_t SurfaceTracing::writeToFile() { | 
|  | 66 | std::scoped_lock lock(mTraceLock); | 
|  | 67 | if (!mEnabled) { | 
|  | 68 | return STATUS_OK; | 
|  | 69 | } | 
|  | 70 | return runner->writeToFile(); | 
|  | 71 | } | 
|  | 72 |  | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 73 | void SurfaceTracing::notify(const char* where) { | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 74 | if (mEnabled) { | 
|  | 75 | runner->notify(where); | 
|  | 76 | } | 
| Vishnu Nair | 60db8c0 | 2020-04-02 11:55:16 -0700 | [diff] [blame] | 77 | } | 
|  | 78 |  | 
|  | 79 | void SurfaceTracing::notifyLocked(const char* where) { | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 80 | if (mEnabled) { | 
|  | 81 | runner->notifyLocked(where); | 
| Vishnu Nair | 60db8c0 | 2020-04-02 11:55:16 -0700 | [diff] [blame] | 82 | } | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 83 | } | 
|  | 84 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 85 | void SurfaceTracing::dump(std::string& result) const { | 
| Vishnu Nair | 9245d3b | 2019-03-22 13:38:56 -0700 | [diff] [blame] | 86 | std::scoped_lock lock(mTraceLock); | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 87 | base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); | 
|  | 88 | if (mEnabled) { | 
|  | 89 | runner->dump(result); | 
|  | 90 | } | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 91 | } | 
|  | 92 |  | 
| Yichi Chen | 9c696ed | 2018-10-01 22:32:30 +0800 | [diff] [blame] | 93 | void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) { | 
|  | 94 | // use the swap trick to make sure memory is released | 
|  | 95 | std::queue<LayersTraceProto>().swap(mStorage); | 
|  | 96 | mSizeInBytes = newSize; | 
|  | 97 | mUsedInBytes = 0U; | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) { | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 101 | size_t protoSize = static_cast<size_t>(proto.ByteSize()); | 
| Yichi Chen | 9c696ed | 2018-10-01 22:32:30 +0800 | [diff] [blame] | 102 | while (mUsedInBytes + protoSize > mSizeInBytes) { | 
|  | 103 | if (mStorage.empty()) { | 
|  | 104 | return; | 
|  | 105 | } | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 106 | mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize()); | 
| Yichi Chen | 9c696ed | 2018-10-01 22:32:30 +0800 | [diff] [blame] | 107 | mStorage.pop(); | 
|  | 108 | } | 
|  | 109 | mUsedInBytes += protoSize; | 
|  | 110 | mStorage.emplace(); | 
|  | 111 | mStorage.back().Swap(&proto); | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) { | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 115 | fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size())); | 
| Yichi Chen | 9c696ed | 2018-10-01 22:32:30 +0800 | [diff] [blame] | 116 |  | 
|  | 117 | while (!mStorage.empty()) { | 
|  | 118 | auto entry = fileProto->add_entry(); | 
|  | 119 | entry->Swap(&mStorage.front()); | 
|  | 120 | mStorage.pop(); | 
|  | 121 | } | 
|  | 122 | } | 
|  | 123 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 124 | SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config) | 
|  | 125 | : mFlinger(flinger), mConfig(config) { | 
|  | 126 | mBuffer.setSize(mConfig.bufferSize); | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 127 | } | 
|  | 128 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 129 | void SurfaceTracing::Runner::notify(const char* where) { | 
|  | 130 | LayersTraceProto entry = traceLayers(where); | 
|  | 131 | mBuffer.emplace(std::move(entry)); | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 132 | } | 
|  | 133 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 134 | status_t SurfaceTracing::Runner::stop() { | 
|  | 135 | return writeToFile(); | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 136 | } | 
|  | 137 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 138 | status_t SurfaceTracing::Runner::writeToFile() { | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 139 | ATRACE_CALL(); | 
|  | 140 |  | 
| Yichi Chen | 9c696ed | 2018-10-01 22:32:30 +0800 | [diff] [blame] | 141 | LayersTraceFileProto fileProto; | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 142 | std::string output; | 
| Yichi Chen | 9c696ed | 2018-10-01 22:32:30 +0800 | [diff] [blame] | 143 |  | 
|  | 144 | fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | | 
|  | 145 | LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); | 
|  | 146 | mBuffer.flush(&fileProto); | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 147 | mBuffer.reset(mConfig.bufferSize); | 
| Yichi Chen | 9c696ed | 2018-10-01 22:32:30 +0800 | [diff] [blame] | 148 |  | 
|  | 149 | if (!fileProto.SerializeToString(&output)) { | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 150 | ALOGE("Could not save the proto file! Permission denied"); | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 151 | return PERMISSION_DENIED; | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 152 | } | 
| chaviw | d1759e0 | 2020-01-23 11:28:09 -0800 | [diff] [blame] | 153 |  | 
|  | 154 | // -rw-r--r-- | 
|  | 155 | const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 156 | if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(), | 
| chaviw | d1759e0 | 2020-01-23 11:28:09 -0800 | [diff] [blame] | 157 | true)) { | 
| Nataniel Borges | 2b796da | 2019-02-15 13:32:18 -0800 | [diff] [blame] | 158 | ALOGE("Could not save the proto file! There are missing fields"); | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 159 | return PERMISSION_DENIED; | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 160 | } | 
|  | 161 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 162 | return NO_ERROR; | 
| Adrian Roos | 1e1a128 | 2017-11-01 19:05:31 +0100 | [diff] [blame] | 163 | } | 
|  | 164 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 165 | LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) { | 
|  | 166 | ATRACE_CALL(); | 
|  | 167 |  | 
|  | 168 | LayersTraceProto entry; | 
|  | 169 | entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); | 
|  | 170 | entry.set_where(where); | 
|  | 171 | LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags)); | 
|  | 172 |  | 
|  | 173 | if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) { | 
|  | 174 | mFlinger.dumpOffscreenLayersProto(layers); | 
|  | 175 | } | 
|  | 176 | entry.mutable_layers()->Swap(&layers); | 
|  | 177 |  | 
|  | 178 | if (flagIsSet(SurfaceTracing::TRACE_HWC)) { | 
|  | 179 | std::string hwcDump; | 
|  | 180 | mFlinger.dumpHwc(hwcDump); | 
|  | 181 | entry.set_hwc_blob(hwcDump); | 
|  | 182 | } | 
|  | 183 | if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) { | 
|  | 184 | entry.set_excludes_composition_state(true); | 
|  | 185 | } | 
|  | 186 | entry.set_missed_entries(mMissedTraceEntries); | 
|  | 187 |  | 
|  | 188 | return entry; | 
|  | 189 | } | 
|  | 190 |  | 
|  | 191 | void SurfaceTracing::Runner::dump(std::string& result) const { | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 192 | base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n", | 
|  | 193 | mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB), | 
|  | 194 | float(mBuffer.size()) / float(1_MB)); | 
| Yichi Chen | adc6961 | 2018-09-15 14:51:18 +0800 | [diff] [blame] | 195 | } | 
|  | 196 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 197 | SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, | 
|  | 198 | std::mutex& sfLock) | 
|  | 199 | : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) { | 
|  | 200 | mEnabled = true; | 
|  | 201 | mThread = std::thread(&AsyncRunner::loop, this); | 
|  | 202 | } | 
| Ady Abraham | b0dbdaa | 2020-01-06 16:19:42 -0800 | [diff] [blame] | 203 |  | 
| Vishnu Nair | 31a8dbc | 2020-10-27 17:37:49 -0700 | [diff] [blame] | 204 | void SurfaceTracing::AsyncRunner::loop() { | 
|  | 205 | while (mEnabled) { | 
|  | 206 | LayersTraceProto entry; | 
|  | 207 | bool entryAdded = traceWhenNotified(&entry); | 
|  | 208 | if (entryAdded) { | 
|  | 209 | mBuffer.emplace(std::move(entry)); | 
|  | 210 | } | 
|  | 211 | if (mWriteToFile) { | 
|  | 212 | Runner::writeToFile(); | 
|  | 213 | mWriteToFile = false; | 
|  | 214 | } | 
|  | 215 | } | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) { | 
|  | 219 | std::unique_lock<std::mutex> lock(mSfLock); | 
|  | 220 | mCanStartTrace.wait(lock); | 
|  | 221 | if (!mAddEntry) { | 
|  | 222 | return false; | 
|  | 223 | } | 
|  | 224 | *outProto = traceLayers(mWhere); | 
|  | 225 | mAddEntry = false; | 
|  | 226 | mMissedTraceEntries = 0; | 
|  | 227 | return true; | 
|  | 228 | } | 
|  | 229 |  | 
|  | 230 | void SurfaceTracing::AsyncRunner::notify(const char* where) { | 
|  | 231 | std::scoped_lock lock(mSfLock); | 
|  | 232 | notifyLocked(where); | 
|  | 233 | } | 
|  | 234 |  | 
|  | 235 | void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) { | 
|  | 236 | mWhere = where; | 
|  | 237 | if (mAddEntry) { | 
|  | 238 | mMissedTraceEntries++; | 
|  | 239 | } | 
|  | 240 | mAddEntry = true; | 
|  | 241 | mCanStartTrace.notify_one(); | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 | status_t SurfaceTracing::AsyncRunner::writeToFile() { | 
|  | 245 | mWriteToFile = true; | 
|  | 246 | mCanStartTrace.notify_one(); | 
|  | 247 | return STATUS_OK; | 
|  | 248 | } | 
|  | 249 |  | 
|  | 250 | status_t SurfaceTracing::AsyncRunner::stop() { | 
|  | 251 | mEnabled = false; | 
|  | 252 | mCanStartTrace.notify_one(); | 
|  | 253 | mThread.join(); | 
|  | 254 | return Runner::writeToFile(); | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 | } // namespace android |