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 31 SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) 32 : mFlinger(flinger), mSfLock(flinger.mDrawingStateLock) {} 33 34 void SurfaceTracing::mainLoop() { 35 addFirstEntry(); 36 bool enabled = true; 37 while (enabled) { 38 LayersTraceProto entry = traceWhenNotified(); 39 enabled = addTraceToBuffer(entry); 40 } 41 } 42 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 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 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 71 void SurfaceTracing::notify(const char* where) { 72 std::scoped_lock lock(mSfLock); 73 mWhere = where; 74 mCanStartTrace.notify_one(); 75 } 76 77 void SurfaceTracing::writeToFileAsync() { 78 std::scoped_lock lock(mTraceLock); 79 mWriteToFile = true; 80 mCanStartTrace.notify_one(); 81 } 82 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 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 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 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 125 status_t SurfaceTracing::writeToFile() { 126 mThread.join(); 127 return mLastErr; 128 } 129 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 143 bool SurfaceTracing::isEnabled() const { 144 std::scoped_lock lock(mTraceLock); 145 return mEnabled; 146 } 147 148 void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) { 149 std::scoped_lock lock(mTraceLock); 150 mBufferSize = bufferSizeInByte; 151 mBuffer.setSize(bufferSizeInByte); 152 } 153 154 void SurfaceTracing::setTraceFlags(uint32_t flags) { 155 std::scoped_lock lock(mSfLock); 156 mTraceFlags = flags; 157 } 158 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 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 195 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