/* * Copyright 2018 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 <dlfcn.h> #include <memory> #include <android/log.h> #include <android/trace.h> namespace gamesdk { class Trace { public: using ATrace_beginSection_type = void (*)(const char *sectionName); using ATrace_endSection_type = void (*)(); using ATrace_isEnabled_type = bool (*)(); Trace() { __android_log_print(ANDROID_LOG_INFO, "Trace", "Unable to load NDK tracing APIs"); } Trace(ATrace_beginSection_type beginSection, ATrace_endSection_type endSection, ATrace_isEnabled_type isEnabled) : ATrace_beginSection(beginSection), ATrace_endSection(endSection), ATrace_isEnabled(isEnabled) {} static std::unique_ptr<Trace> create() { void *libandroid = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL); if (!libandroid) { return std::make_unique<Trace>(); } auto beginSection = reinterpret_cast<ATrace_beginSection_type>( dlsym(libandroid, "ATrace_beginSection")); if (!beginSection) { return std::make_unique<Trace>(); } auto endSection = reinterpret_cast<ATrace_endSection_type>( dlsym(libandroid, "ATrace_endSection")); if (!endSection) { return std::make_unique<Trace>(); } auto isEnabled = reinterpret_cast<ATrace_isEnabled_type>( dlsym(libandroid, "ATrace_isEnabled")); if (!isEnabled) { return std::make_unique<Trace>(); } return std::make_unique<Trace>(beginSection, endSection, isEnabled); } bool isAvailable() const { return ATrace_beginSection != nullptr; } bool isEnabled() const { return (ATrace_isEnabled != nullptr) && ATrace_isEnabled(); } void beginSection(const char *name) const { if (!ATrace_beginSection) { return; } ATrace_beginSection(name); } void endSection() const { if (!ATrace_endSection) { return; } ATrace_endSection(); } static Trace *getInstance() { static std::unique_ptr<Trace> trace = Trace::create(); return trace.get(); }; private: const ATrace_beginSection_type ATrace_beginSection = nullptr; const ATrace_endSection_type ATrace_endSection = nullptr; const ATrace_isEnabled_type ATrace_isEnabled = nullptr; }; struct ScopedTrace { ScopedTrace(const char *name) { Trace *trace = Trace::getInstance(); if (!trace->isAvailable() || !trace->isEnabled()) { return; } trace->beginSection(name); mIsTracing = true; } ~ScopedTrace() { if (!mIsTracing) { return; } Trace *trace = Trace::getInstance(); trace->endSection(); } private: bool mIsTracing = false; }; } // namespace gamesdk #define PASTE_HELPER_HELPER(a, b) a ## b #define PASTE_HELPER(a, b) PASTE_HELPER_HELPER(a, b) #define TRACE_CALL() gamesdk::ScopedTrace PASTE_HELPER(scopedTrace, __LINE__)(__PRETTY_FUNCTION__)