/* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include using namespace android::surfaceflinger; namespace android { class SurfaceFlinger; constexpr auto operator""_MB(unsigned long long const num) { return num * 1024 * 1024; } /* * SurfaceTracing records layer states during surface flinging. Manages tracing state and * configuration. */ class SurfaceTracing { public: SurfaceTracing(SurfaceFlinger& flinger); bool enable(); bool disable(); status_t writeToFile(); bool isEnabled() const; /* * Adds a trace entry, must be called from the drawing thread or while holding the * SurfaceFlinger tracing lock. */ void notify(const char* where); /* * Adds a trace entry, called while holding the SurfaceFlinger tracing lock. */ void notifyLocked(const char* where) /* REQUIRES(mSfLock) */; void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; } void dump(std::string& result) const; enum : uint32_t { TRACE_CRITICAL = 1 << 0, TRACE_INPUT = 1 << 1, TRACE_COMPOSITION = 1 << 2, TRACE_EXTRA = 1 << 3, TRACE_HWC = 1 << 4, // Add non-geometry composition changes to the trace. TRACE_BUFFERS = 1 << 5, // Add entries from the drawing thread post composition. TRACE_SYNC = 1 << 6, TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA, }; void setTraceFlags(uint32_t flags) { mConfig.flags = flags; } bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } private: class Runner; static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB; static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb"; SurfaceFlinger& mFlinger; mutable std::mutex mTraceLock; bool mEnabled GUARDED_BY(mTraceLock) = false; std::unique_ptr runner GUARDED_BY(mTraceLock); struct Config { uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC; size_t bufferSize = DEFAULT_BUFFER_SIZE; } mConfig; /* * ring buffer. */ class LayersTraceBuffer { public: size_t size() const { return mSizeInBytes; } size_t used() const { return mUsedInBytes; } size_t frameCount() const { return mStorage.size(); } void setSize(size_t newSize) { mSizeInBytes = newSize; } void reset(size_t newSize); void emplace(LayersTraceProto&& proto); void flush(LayersTraceFileProto* fileProto); private: size_t mUsedInBytes = 0U; size_t mSizeInBytes = DEFAULT_BUFFER_SIZE; std::queue mStorage; }; /* * Implements a synchronous way of adding trace entries. This must be called * from the drawing thread. */ class Runner { public: Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config); virtual ~Runner() = default; virtual status_t stop(); virtual status_t writeToFile(); virtual void notify(const char* where); /* Cannot be called with a synchronous runner. */ virtual void notifyLocked(const char* /* where */) {} void dump(std::string& result) const; protected: bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } SurfaceFlinger& mFlinger; SurfaceTracing::Config mConfig; SurfaceTracing::LayersTraceBuffer mBuffer; uint32_t mMissedTraceEntries = 0; LayersTraceProto traceLayers(const char* where); }; /* * Implements asynchronous way to add trace entries called from a separate thread while holding * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not * scheduled in time. */ class AsyncRunner : public Runner { public: AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock); virtual ~AsyncRunner() = default; status_t stop() override; status_t writeToFile() override; void notify(const char* where) override; void notifyLocked(const char* where); private: std::mutex& mSfLock; std::condition_variable mCanStartTrace; std::thread mThread; const char* mWhere = ""; bool mWriteToFile = false; bool mEnabled = false; bool mAddEntry = false; void loop(); bool traceWhenNotified(LayersTraceProto* outProto); }; }; } // namespace android