/* * Copyright (C) 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. */ #include "android-base/macros.h" #include "gc/scoped_gc_critical_section.h" #include "instrumentation.h" #include "runtime.h" #include "runtime_callbacks.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" #include "thread_list.h" namespace tracefast { #if ((!defined(TRACEFAST_INTERPRETER) && !defined(TRACEFAST_TRAMPOLINE)) || \ (defined(TRACEFAST_INTERPRETER) && defined(TRACEFAST_TRAMPOLINE))) #error Must set one of TRACEFAST_TRAMPOLINE or TRACEFAST_INTERPRETER during build #endif #ifdef TRACEFAST_INTERPRETER static constexpr const char* kTracerInstrumentationKey = "tracefast_INTERPRETER"; static constexpr bool kNeedsInterpreter = true; #else // defined(TRACEFAST_TRAMPOLINE) static constexpr const char* kTracerInstrumentationKey = "tracefast_TRAMPOLINE"; static constexpr bool kNeedsInterpreter = false; #endif // TRACEFAST_INITERPRETER class Tracer final : public art::instrumentation::InstrumentationListener { public: Tracer() {} void MethodEntered([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::ArtMethod* method) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void MethodExited([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] art::instrumentation::OptionalFrame frame, [[maybe_unused]] art::MutableHandle& return_value) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void MethodExited([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] art::instrumentation::OptionalFrame frame, [[maybe_unused]] art::JValue& return_value) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void MethodUnwind([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] uint32_t dex_pc) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void DexPcMoved([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::Handle this_object, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] uint32_t new_dex_pc) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void FieldRead([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::Handle this_object, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] uint32_t dex_pc, [[maybe_unused]] art::ArtField* field) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void FieldWritten([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::Handle this_object, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] uint32_t dex_pc, [[maybe_unused]] art::ArtField* field, [[maybe_unused]] art::Handle field_value) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void FieldWritten([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::Handle this_object, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] uint32_t dex_pc, [[maybe_unused]] art::ArtField* field, [[maybe_unused]] const art::JValue& field_value) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void ExceptionThrown([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::Handle exception_object) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void ExceptionHandled([[maybe_unused]] art::Thread* self, [[maybe_unused]] art::Handle throwable) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void Branch([[maybe_unused]] art::Thread* thread, [[maybe_unused]] art::ArtMethod* method, [[maybe_unused]] uint32_t dex_pc, [[maybe_unused]] int32_t dex_pc_offset) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} void WatchedFramePop([[maybe_unused]] art::Thread* thread, [[maybe_unused]] const art::ShadowFrame& frame) override REQUIRES_SHARED(art::Locks::mutator_lock_) {} private: DISALLOW_COPY_AND_ASSIGN(Tracer); }; Tracer gEmptyTracer; static void StartTracing() REQUIRES(!art::Locks::mutator_lock_, !art::Locks::thread_list_lock_, !art::Locks::thread_suspend_count_lock_) { art::Thread* self = art::Thread::Current(); art::Runtime* runtime = art::Runtime::Current(); art::gc::ScopedGCCriticalSection gcs(self, art::gc::kGcCauseInstrumentation, art::gc::kCollectorTypeInstrumentation); art::ScopedSuspendAll ssa("starting fast tracing"); runtime->GetInstrumentation()->AddListener(&gEmptyTracer, art::instrumentation::Instrumentation::kMethodEntered | art::instrumentation::Instrumentation::kMethodExited | art::instrumentation::Instrumentation::kMethodUnwind); runtime->GetInstrumentation()->EnableMethodTracing( kTracerInstrumentationKey, &gEmptyTracer, kNeedsInterpreter); } class TraceFastPhaseCB : public art::RuntimePhaseCallback { public: TraceFastPhaseCB() {} void NextRuntimePhase(art::RuntimePhaseCallback::RuntimePhase phase) override REQUIRES_SHARED(art::Locks::mutator_lock_) { if (phase == art::RuntimePhaseCallback::RuntimePhase::kInit) { art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kWaitingForMethodTracingStart); StartTracing(); } } }; TraceFastPhaseCB gPhaseCallback; // The plugin initialization function. extern "C" bool ArtPlugin_Initialize() { art::Runtime* runtime = art::Runtime::Current(); art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kWaitingForMethodTracingStart); art::ScopedSuspendAll ssa("Add phase callback"); runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gPhaseCallback); return true; } extern "C" bool ArtPlugin_Deinitialize() { // Don't need to bother doing anything. return true; } } // namespace tracefast