xref: /aosp_15_r20/art/tools/jvmti-agents/titrace/titrace.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker // Copyright (C) 2017 The Android Open Source Project
2*795d594fSAndroid Build Coastguard Worker //
3*795d594fSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*795d594fSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*795d594fSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*795d594fSAndroid Build Coastguard Worker //
7*795d594fSAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*795d594fSAndroid Build Coastguard Worker //
9*795d594fSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*795d594fSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*795d594fSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*795d594fSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*795d594fSAndroid Build Coastguard Worker // limitations under the License.
14*795d594fSAndroid Build Coastguard Worker //
15*795d594fSAndroid Build Coastguard Worker 
16*795d594fSAndroid Build Coastguard Worker #include "instruction_decoder.h"
17*795d594fSAndroid Build Coastguard Worker 
18*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
19*795d594fSAndroid Build Coastguard Worker #include <atomic>
20*795d594fSAndroid Build Coastguard Worker #include <jni.h>
21*795d594fSAndroid Build Coastguard Worker #include <jvmti.h>
22*795d594fSAndroid Build Coastguard Worker #include <map>
23*795d594fSAndroid Build Coastguard Worker #include <memory>
24*795d594fSAndroid Build Coastguard Worker #include <mutex>
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker // We could probably return a JNI_ERR here but lets crash instead if something fails.
27*795d594fSAndroid Build Coastguard Worker #define CHECK_JVMTI_ERROR(jvmti, errnum) \
28*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(JVMTI_ERROR_NONE, (errnum)) << GetJvmtiErrorString((jvmti), (errnum)) << (" ")
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker namespace titrace {
31*795d594fSAndroid Build Coastguard Worker 
GetJvmtiErrorString(jvmtiEnv * jvmti,jvmtiError errnum)32*795d594fSAndroid Build Coastguard Worker static const char* GetJvmtiErrorString(jvmtiEnv* jvmti, jvmtiError errnum) {
33*795d594fSAndroid Build Coastguard Worker   char* errnum_str = nullptr;
34*795d594fSAndroid Build Coastguard Worker   jvmti->GetErrorName(errnum, /*out*/ &errnum_str);
35*795d594fSAndroid Build Coastguard Worker   if (errnum_str == nullptr) {
36*795d594fSAndroid Build Coastguard Worker     return "Unknown";
37*795d594fSAndroid Build Coastguard Worker   }
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker   return errnum_str;
40*795d594fSAndroid Build Coastguard Worker }
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker // Type-safe wrapper for JVMTI-allocated memory.
43*795d594fSAndroid Build Coastguard Worker // Deallocates with jvmtiEnv::Deallocate.
44*795d594fSAndroid Build Coastguard Worker template <typename T>
45*795d594fSAndroid Build Coastguard Worker struct TiMemory {
TiMemorytitrace::TiMemory46*795d594fSAndroid Build Coastguard Worker   explicit TiMemory(jvmtiEnv* env, T* mem, size_t size) : env_(env), mem_(mem), size_(size) {
47*795d594fSAndroid Build Coastguard Worker   }
48*795d594fSAndroid Build Coastguard Worker 
~TiMemorytitrace::TiMemory49*795d594fSAndroid Build Coastguard Worker   ~TiMemory() {
50*795d594fSAndroid Build Coastguard Worker     if (mem_ != nullptr) {
51*795d594fSAndroid Build Coastguard Worker       env_->Deallocate(static_cast<unsigned char*>(mem_));
52*795d594fSAndroid Build Coastguard Worker     }
53*795d594fSAndroid Build Coastguard Worker     mem_ = nullptr;
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker   TiMemory(const TiMemory& other) = delete;
TiMemorytitrace::TiMemory57*795d594fSAndroid Build Coastguard Worker   TiMemory(TiMemory&& other) noexcept {
58*795d594fSAndroid Build Coastguard Worker     env_ = other.env_;
59*795d594fSAndroid Build Coastguard Worker     mem_ = other.mem_;
60*795d594fSAndroid Build Coastguard Worker     size_ = other.size_;
61*795d594fSAndroid Build Coastguard Worker 
62*795d594fSAndroid Build Coastguard Worker     if (this != &other) {
63*795d594fSAndroid Build Coastguard Worker       other.env_ = nullptr;
64*795d594fSAndroid Build Coastguard Worker       other.mem_ = nullptr;
65*795d594fSAndroid Build Coastguard Worker       other.size_ = 0u;
66*795d594fSAndroid Build Coastguard Worker     }
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker 
operator =titrace::TiMemory69*795d594fSAndroid Build Coastguard Worker   TiMemory& operator=(TiMemory&& other) noexcept {
70*795d594fSAndroid Build Coastguard Worker     if (mem_ != other.mem_) {
71*795d594fSAndroid Build Coastguard Worker       TiMemory::~TiMemory();
72*795d594fSAndroid Build Coastguard Worker     }
73*795d594fSAndroid Build Coastguard Worker     new (this) TiMemory(std::move(other));
74*795d594fSAndroid Build Coastguard Worker     return *this;
75*795d594fSAndroid Build Coastguard Worker   }
76*795d594fSAndroid Build Coastguard Worker 
GetMemorytitrace::TiMemory77*795d594fSAndroid Build Coastguard Worker   T* GetMemory() {
78*795d594fSAndroid Build Coastguard Worker     return mem_;
79*795d594fSAndroid Build Coastguard Worker   }
80*795d594fSAndroid Build Coastguard Worker 
Sizetitrace::TiMemory81*795d594fSAndroid Build Coastguard Worker   size_t Size() {
82*795d594fSAndroid Build Coastguard Worker     return size_ / sizeof(T);
83*795d594fSAndroid Build Coastguard Worker   }
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker  private:
86*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* env_;
87*795d594fSAndroid Build Coastguard Worker   T* mem_;
88*795d594fSAndroid Build Coastguard Worker   size_t size_;
89*795d594fSAndroid Build Coastguard Worker };
90*795d594fSAndroid Build Coastguard Worker 
91*795d594fSAndroid Build Coastguard Worker struct MethodBytecode {
MethodBytecodetitrace::MethodBytecode92*795d594fSAndroid Build Coastguard Worker   explicit MethodBytecode(jvmtiEnv* env, unsigned char* memory, jint size)
93*795d594fSAndroid Build Coastguard Worker       : bytecode_(env, memory, static_cast<size_t>(size)) {
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   TiMemory<uint8_t> bytecode_;
97*795d594fSAndroid Build Coastguard Worker };
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker struct TraceStatistics {
Initializetitrace::TraceStatistics100*795d594fSAndroid Build Coastguard Worker   static void Initialize(jvmtiEnv* jvmti) {
101*795d594fSAndroid Build Coastguard Worker     TraceStatistics& stats = GetSingleton();
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker     bool is_ri = true;
104*795d594fSAndroid Build Coastguard Worker     {
105*795d594fSAndroid Build Coastguard Worker       jvmtiError error;
106*795d594fSAndroid Build Coastguard Worker       char* value_ptr;
107*795d594fSAndroid Build Coastguard Worker       error = jvmti->GetSystemProperty("java.vm.name", /*out*/ &value_ptr);
108*795d594fSAndroid Build Coastguard Worker       CHECK_JVMTI_ERROR(jvmti, error) << "Failed to get property 'java.vm.name'";
109*795d594fSAndroid Build Coastguard Worker       CHECK(value_ptr != nullptr) << "Returned property was null for 'java.vm.name'";
110*795d594fSAndroid Build Coastguard Worker 
111*795d594fSAndroid Build Coastguard Worker       if (strcmp("Dalvik", value_ptr) == 0) {
112*795d594fSAndroid Build Coastguard Worker         is_ri = false;
113*795d594fSAndroid Build Coastguard Worker       }
114*795d594fSAndroid Build Coastguard Worker     }
115*795d594fSAndroid Build Coastguard Worker 
116*795d594fSAndroid Build Coastguard Worker     InstructionFileFormat format =
117*795d594fSAndroid Build Coastguard Worker         is_ri ? InstructionFileFormat::kClass : InstructionFileFormat::kDex;
118*795d594fSAndroid Build Coastguard Worker     stats.instruction_decoder_.reset(InstructionDecoder::NewInstance(format));
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker     CHECK_GE(arraysize(stats.instruction_counter_),
121*795d594fSAndroid Build Coastguard Worker              stats.instruction_decoder_->GetMaximumOpcode());
122*795d594fSAndroid Build Coastguard Worker   }
123*795d594fSAndroid Build Coastguard Worker 
GetSingletontitrace::TraceStatistics124*795d594fSAndroid Build Coastguard Worker   static TraceStatistics& GetSingleton() {
125*795d594fSAndroid Build Coastguard Worker     static TraceStatistics stats;
126*795d594fSAndroid Build Coastguard Worker     return stats;
127*795d594fSAndroid Build Coastguard Worker   }
128*795d594fSAndroid Build Coastguard Worker 
Logtitrace::TraceStatistics129*795d594fSAndroid Build Coastguard Worker   void Log() {
130*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "================================================";
131*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "              TI Trace // Summary               ";
132*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "++++++++++++++++++++++++++++++++++++++++++++++++";
133*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "  * Single step counter: " << single_step_counter_;
134*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "+++++++++++    Instructions Count   ++++++++++++";
135*795d594fSAndroid Build Coastguard Worker 
136*795d594fSAndroid Build Coastguard Worker     size_t total = single_step_counter_;
137*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < arraysize(instruction_counter_); ++i) {
138*795d594fSAndroid Build Coastguard Worker       size_t inst_count = instruction_counter_[i];
139*795d594fSAndroid Build Coastguard Worker       if (inst_count > 0) {
140*795d594fSAndroid Build Coastguard Worker         const char* opcode_name = instruction_decoder_->GetName(i);
141*795d594fSAndroid Build Coastguard Worker         LOG(INFO) << "  * " << opcode_name << "(op:" << i << "), count: " << inst_count
142*795d594fSAndroid Build Coastguard Worker                   << ", % of total: " << (100.0 * inst_count / total);
143*795d594fSAndroid Build Coastguard Worker       }
144*795d594fSAndroid Build Coastguard Worker     }
145*795d594fSAndroid Build Coastguard Worker 
146*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "------------------------------------------------";
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker 
OnSingleSteptitrace::TraceStatistics149*795d594fSAndroid Build Coastguard Worker   void OnSingleStep(jvmtiEnv* jvmti_env, jmethodID method, jlocation location) {
150*795d594fSAndroid Build Coastguard Worker     // Counters do not need a happens-before.
151*795d594fSAndroid Build Coastguard Worker     // Use the weakest memory order simply to avoid tearing.
152*795d594fSAndroid Build Coastguard Worker     single_step_counter_.fetch_add(1u, std::memory_order_relaxed);
153*795d594fSAndroid Build Coastguard Worker 
154*795d594fSAndroid Build Coastguard Worker     MethodBytecode& bytecode = LookupBytecode(jvmti_env, method);
155*795d594fSAndroid Build Coastguard Worker 
156*795d594fSAndroid Build Coastguard Worker     // Decode jlocation value that depends on the bytecode format.
157*795d594fSAndroid Build Coastguard Worker     size_t actual_location = instruction_decoder_->LocationToOffset(static_cast<size_t>(location));
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker     // Decode the exact instruction and increment its counter.
160*795d594fSAndroid Build Coastguard Worker     CHECK_LE(actual_location, bytecode.bytecode_.Size());
161*795d594fSAndroid Build Coastguard Worker     RecordInstruction(bytecode.bytecode_.GetMemory() + actual_location);
162*795d594fSAndroid Build Coastguard Worker   }
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker  private:
RecordInstructiontitrace::TraceStatistics165*795d594fSAndroid Build Coastguard Worker   void RecordInstruction(const uint8_t* instruction) {
166*795d594fSAndroid Build Coastguard Worker     uint8_t opcode = instruction[0];
167*795d594fSAndroid Build Coastguard Worker     // Counters do not need a happens-before.
168*795d594fSAndroid Build Coastguard Worker     // Use the weakest memory order simply to avoid tearing.
169*795d594fSAndroid Build Coastguard Worker     instruction_counter_[opcode].fetch_add(1u, std::memory_order_relaxed);
170*795d594fSAndroid Build Coastguard Worker   }
171*795d594fSAndroid Build Coastguard Worker 
LookupBytecodetitrace::TraceStatistics172*795d594fSAndroid Build Coastguard Worker   MethodBytecode& LookupBytecode(jvmtiEnv* jvmti_env, jmethodID method) {
173*795d594fSAndroid Build Coastguard Worker     jvmtiError error;
174*795d594fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(bytecode_cache_mutex_);
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker     auto it = bytecode_cache_.find(method);
177*795d594fSAndroid Build Coastguard Worker     if (it == bytecode_cache_.end()) {
178*795d594fSAndroid Build Coastguard Worker       jint bytecode_count_ptr = 0;
179*795d594fSAndroid Build Coastguard Worker       unsigned char* bytecodes_ptr = nullptr;
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker       error = jvmti_env->GetBytecodes(method, &bytecode_count_ptr, &bytecodes_ptr);
182*795d594fSAndroid Build Coastguard Worker       CHECK_JVMTI_ERROR(jvmti_env, error) << "Failed to get bytecodes for method " << method;
183*795d594fSAndroid Build Coastguard Worker       CHECK(bytecodes_ptr != nullptr) << "Bytecode ptr was null for method " << method;
184*795d594fSAndroid Build Coastguard Worker       CHECK_GE(bytecode_count_ptr, 0) << "Bytecode size too small for method " << method;
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker       // std::pair<iterator, bool inserted>
187*795d594fSAndroid Build Coastguard Worker       auto&& pair = bytecode_cache_.insert(
188*795d594fSAndroid Build Coastguard Worker           std::make_pair(method, MethodBytecode(jvmti_env, bytecodes_ptr, bytecode_count_ptr)));
189*795d594fSAndroid Build Coastguard Worker       it = pair.first;
190*795d594fSAndroid Build Coastguard Worker     }
191*795d594fSAndroid Build Coastguard Worker 
192*795d594fSAndroid Build Coastguard Worker     // Returning the address is safe. if map is resized, the contents will not move.
193*795d594fSAndroid Build Coastguard Worker     return it->second;
194*795d594fSAndroid Build Coastguard Worker   }
195*795d594fSAndroid Build Coastguard Worker 
196*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<InstructionDecoder> instruction_decoder_;
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker   std::atomic<size_t> single_step_counter_{0u};
199*795d594fSAndroid Build Coastguard Worker   std::atomic<size_t> instruction_counter_[256]{};
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker   // Cache the bytecode to avoid calling into JVMTI repeatedly.
202*795d594fSAndroid Build Coastguard Worker   // TODO: invalidate if the bytecode was updated?
203*795d594fSAndroid Build Coastguard Worker   std::map<jmethodID, MethodBytecode> bytecode_cache_;
204*795d594fSAndroid Build Coastguard Worker   // bytecode cache is thread-safe.
205*795d594fSAndroid Build Coastguard Worker   std::mutex bytecode_cache_mutex_;
206*795d594fSAndroid Build Coastguard Worker };
207*795d594fSAndroid Build Coastguard Worker 
208*795d594fSAndroid Build Coastguard Worker struct EventCallbacks {
SingleSteptitrace::EventCallbacks209*795d594fSAndroid Build Coastguard Worker   static void SingleStep(jvmtiEnv* jvmti_env,
210*795d594fSAndroid Build Coastguard Worker                          [[maybe_unused]] JNIEnv* jni_env,
211*795d594fSAndroid Build Coastguard Worker                          [[maybe_unused]] jthread thread,
212*795d594fSAndroid Build Coastguard Worker                          jmethodID method,
213*795d594fSAndroid Build Coastguard Worker                          jlocation location) {
214*795d594fSAndroid Build Coastguard Worker     TraceStatistics& stats = TraceStatistics::GetSingleton();
215*795d594fSAndroid Build Coastguard Worker     stats.OnSingleStep(jvmti_env, method, location);
216*795d594fSAndroid Build Coastguard Worker   }
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker   // Use "kill -SIGQUIT" to generate a data dump request.
219*795d594fSAndroid Build Coastguard Worker   // Useful when running an android app since it doesn't go through
220*795d594fSAndroid Build Coastguard Worker   // a normal Agent_OnUnload.
DataDumpRequesttitrace::EventCallbacks221*795d594fSAndroid Build Coastguard Worker   static void DataDumpRequest([[maybe_unused]] jvmtiEnv* jvmti_env) {
222*795d594fSAndroid Build Coastguard Worker     TraceStatistics& stats = TraceStatistics::GetSingleton();
223*795d594fSAndroid Build Coastguard Worker     stats.Log();
224*795d594fSAndroid Build Coastguard Worker   }
225*795d594fSAndroid Build Coastguard Worker };
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker }  // namespace titrace
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker // Late attachment (e.g. 'am attach-agent').
Agent_OnAttach(JavaVM * vm,char * options,void * reserved)230*795d594fSAndroid Build Coastguard Worker JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char* options, void* reserved) {
231*795d594fSAndroid Build Coastguard Worker   return Agent_OnLoad(vm, options, reserved);
232*795d594fSAndroid Build Coastguard Worker }
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker // Early attachment (e.g. 'java -agent[lib|path]:filename.so').
Agent_OnLoad(JavaVM * jvm,char *,void *)235*795d594fSAndroid Build Coastguard Worker JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* jvm,
236*795d594fSAndroid Build Coastguard Worker                                     char* /* options */,
237*795d594fSAndroid Build Coastguard Worker                                     void* /* reserved */) {
238*795d594fSAndroid Build Coastguard Worker   using namespace titrace;  // NOLINT [build/namespaces] [5]
239*795d594fSAndroid Build Coastguard Worker 
240*795d594fSAndroid Build Coastguard Worker   android::base::InitLogging(/* argv= */nullptr);
241*795d594fSAndroid Build Coastguard Worker 
242*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* jvmti = nullptr;
243*795d594fSAndroid Build Coastguard Worker   {
244*795d594fSAndroid Build Coastguard Worker     jint res = 0;
245*795d594fSAndroid Build Coastguard Worker     // Magic number that the agent can use to attach to non-debuggable apps on userdebug.
246*795d594fSAndroid Build Coastguard Worker     constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
247*795d594fSAndroid Build Coastguard Worker     res = jvm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_1);
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker     if (res != JNI_OK || jvmti == nullptr) {
250*795d594fSAndroid Build Coastguard Worker       res = jvm->GetEnv(reinterpret_cast<void**>(&jvmti), kArtTiVersion);
251*795d594fSAndroid Build Coastguard Worker     }
252*795d594fSAndroid Build Coastguard Worker     if (res != JNI_OK || jvmti == nullptr) {
253*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unable to access JVMTI, error code " << res;
254*795d594fSAndroid Build Coastguard Worker     }
255*795d594fSAndroid Build Coastguard Worker   }
256*795d594fSAndroid Build Coastguard Worker 
257*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "Agent_OnLoad: Hello World";
258*795d594fSAndroid Build Coastguard Worker 
259*795d594fSAndroid Build Coastguard Worker   {
260*795d594fSAndroid Build Coastguard Worker     // Initialize our instruction file-format decoder.
261*795d594fSAndroid Build Coastguard Worker     TraceStatistics::Initialize(jvmti);
262*795d594fSAndroid Build Coastguard Worker   }
263*795d594fSAndroid Build Coastguard Worker 
264*795d594fSAndroid Build Coastguard Worker   jvmtiError error{};
265*795d594fSAndroid Build Coastguard Worker 
266*795d594fSAndroid Build Coastguard Worker   // Set capabilities.
267*795d594fSAndroid Build Coastguard Worker   {
268*795d594fSAndroid Build Coastguard Worker     jvmtiCapabilities caps = {};
269*795d594fSAndroid Build Coastguard Worker     caps.can_generate_single_step_events = 1;
270*795d594fSAndroid Build Coastguard Worker     caps.can_get_bytecodes = 1;
271*795d594fSAndroid Build Coastguard Worker 
272*795d594fSAndroid Build Coastguard Worker     error = jvmti->AddCapabilities(&caps);
273*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI_ERROR(jvmti, error)
274*795d594fSAndroid Build Coastguard Worker       << "Unable to get necessary JVMTI capabilities";
275*795d594fSAndroid Build Coastguard Worker   }
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker   // Set callbacks.
278*795d594fSAndroid Build Coastguard Worker   {
279*795d594fSAndroid Build Coastguard Worker     jvmtiEventCallbacks callbacks = {};
280*795d594fSAndroid Build Coastguard Worker     callbacks.SingleStep = &EventCallbacks::SingleStep;
281*795d594fSAndroid Build Coastguard Worker     callbacks.DataDumpRequest = &EventCallbacks::DataDumpRequest;
282*795d594fSAndroid Build Coastguard Worker 
283*795d594fSAndroid Build Coastguard Worker     error = jvmti->SetEventCallbacks(&callbacks,
284*795d594fSAndroid Build Coastguard Worker                                      static_cast<jint>(sizeof(callbacks)));
285*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI_ERROR(jvmti, error) << "Unable to set event callbacks";
286*795d594fSAndroid Build Coastguard Worker   }
287*795d594fSAndroid Build Coastguard Worker 
288*795d594fSAndroid Build Coastguard Worker   // Enable events notification.
289*795d594fSAndroid Build Coastguard Worker   {
290*795d594fSAndroid Build Coastguard Worker     error = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
291*795d594fSAndroid Build Coastguard Worker                                             JVMTI_EVENT_SINGLE_STEP,
292*795d594fSAndroid Build Coastguard Worker                                             nullptr /* all threads */);
293*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI_ERROR(jvmti, error)
294*795d594fSAndroid Build Coastguard Worker       << "Failed to enable SINGLE_STEP notification";
295*795d594fSAndroid Build Coastguard Worker 
296*795d594fSAndroid Build Coastguard Worker     error = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
297*795d594fSAndroid Build Coastguard Worker                                             JVMTI_EVENT_DATA_DUMP_REQUEST,
298*795d594fSAndroid Build Coastguard Worker                                             nullptr /* all threads */);
299*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI_ERROR(jvmti, error)
300*795d594fSAndroid Build Coastguard Worker       << "Failed to enable DATA_DUMP_REQUEST notification";
301*795d594fSAndroid Build Coastguard Worker   }
302*795d594fSAndroid Build Coastguard Worker 
303*795d594fSAndroid Build Coastguard Worker   return JNI_OK;
304*795d594fSAndroid Build Coastguard Worker }
305*795d594fSAndroid Build Coastguard Worker 
306*795d594fSAndroid Build Coastguard Worker // Note: This is not called for normal Android apps,
307*795d594fSAndroid Build Coastguard Worker // use "kill -SIGQUIT" instead to generate a data dump request.
Agent_OnUnload(JavaVM * vm)308*795d594fSAndroid Build Coastguard Worker JNIEXPORT void JNICALL Agent_OnUnload([[maybe_unused]] JavaVM* vm) {
309*795d594fSAndroid Build Coastguard Worker   using namespace titrace;  // NOLINT [build/namespaces] [5]
310*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "Agent_OnUnload: Goodbye";
311*795d594fSAndroid Build Coastguard Worker 
312*795d594fSAndroid Build Coastguard Worker   TraceStatistics::GetSingleton().Log();
313*795d594fSAndroid Build Coastguard Worker }
314