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