Home | History | Annotate | Download | only in surfaceflinger
      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