xref: /aosp_15_r20/art/tools/jvmti-agents/simple-profile/simple_profile.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker // Copyright (C) 2020 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 <android-base/logging.h>
17*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
18*795d594fSAndroid Build Coastguard Worker #include <jni.h>
19*795d594fSAndroid Build Coastguard Worker #include <jvmti.h>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include <atomic>
22*795d594fSAndroid Build Coastguard Worker #include <cstring>
23*795d594fSAndroid Build Coastguard Worker #include <iomanip>
24*795d594fSAndroid Build Coastguard Worker #include <iostream>
25*795d594fSAndroid Build Coastguard Worker #include <memory>
26*795d594fSAndroid Build Coastguard Worker #include <sstream>
27*795d594fSAndroid Build Coastguard Worker #include <string>
28*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
29*795d594fSAndroid Build Coastguard Worker #include <utility>
30*795d594fSAndroid Build Coastguard Worker #include <vector>
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker #include "android-base/unique_fd.h"
33*795d594fSAndroid Build Coastguard Worker #include "nativehelper/scoped_local_ref.h"
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker namespace simple_profile {
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker #define CHECK_JVMTI(a) CHECK_EQ(JVMTI_ERROR_NONE, a)
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker struct DataDefinition {
42*795d594fSAndroid Build Coastguard Worker   std::string_view class_name;
43*795d594fSAndroid Build Coastguard Worker   std::string_view method_name;
44*795d594fSAndroid Build Coastguard Worker   std::string_view method_descriptor;
45*795d594fSAndroid Build Coastguard Worker   uint64_t count;
46*795d594fSAndroid Build Coastguard Worker };
47*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const DataDefinition & dd)48*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const DataDefinition& dd) {
49*795d594fSAndroid Build Coastguard Worker   return os << "{\"class_name\":\"" << dd.class_name << "\",\"method_name\":\"" << dd.method_name
50*795d594fSAndroid Build Coastguard Worker             << "\",\"method_descriptor\":\"" << dd.method_descriptor << "\",\"count\":" << dd.count
51*795d594fSAndroid Build Coastguard Worker             << "}";
52*795d594fSAndroid Build Coastguard Worker }
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker class SimpleProfileData {
55*795d594fSAndroid Build Coastguard Worker  public:
SimpleProfileData(jvmtiEnv * env,std::string out_fd_name,int fd,bool dump_on_shutdown,bool dump_on_main_stop)56*795d594fSAndroid Build Coastguard Worker   SimpleProfileData(
57*795d594fSAndroid Build Coastguard Worker       jvmtiEnv* env, std::string out_fd_name, int fd, bool dump_on_shutdown, bool dump_on_main_stop)
58*795d594fSAndroid Build Coastguard Worker       : dump_id_(0),
59*795d594fSAndroid Build Coastguard Worker         out_fd_name_(std::move(out_fd_name)),
60*795d594fSAndroid Build Coastguard Worker         out_fd_(fd),
61*795d594fSAndroid Build Coastguard Worker         shutdown_(false),
62*795d594fSAndroid Build Coastguard Worker         dump_on_shutdown_(dump_on_shutdown || dump_on_main_stop),
63*795d594fSAndroid Build Coastguard Worker         dump_on_main_stop_(dump_on_main_stop) {
64*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(env->CreateRawMonitor("simple_profile_mon", &mon_));
65*795d594fSAndroid Build Coastguard Worker     method_counts_.reserve(10000);
66*795d594fSAndroid Build Coastguard Worker   }
67*795d594fSAndroid Build Coastguard Worker 
68*795d594fSAndroid Build Coastguard Worker   void Dump(jvmtiEnv* jvmti);
69*795d594fSAndroid Build Coastguard Worker   void Enter(jvmtiEnv* jvmti, JNIEnv* env, jmethodID meth);
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker   void RunDumpLoop(jvmtiEnv* jvmti, JNIEnv* env);
72*795d594fSAndroid Build Coastguard Worker 
GetProfileData(jvmtiEnv * env)73*795d594fSAndroid Build Coastguard Worker   static SimpleProfileData* GetProfileData(jvmtiEnv* env) {
74*795d594fSAndroid Build Coastguard Worker     void* data;
75*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(env->GetEnvironmentLocalStorage(&data));
76*795d594fSAndroid Build Coastguard Worker     return static_cast<SimpleProfileData*>(data);
77*795d594fSAndroid Build Coastguard Worker   }
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   void FinishInitialization(jvmtiEnv* jvmti, JNIEnv* jni, jthread cur);
80*795d594fSAndroid Build Coastguard Worker   void Shutdown(jvmtiEnv* jvmti, JNIEnv* jni);
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker  private:
83*795d594fSAndroid Build Coastguard Worker   void DoDump(jvmtiEnv* jvmti, JNIEnv* jni, const std::unordered_map<jmethodID, uint64_t>& copy);
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker   jlong dump_id_;
86*795d594fSAndroid Build Coastguard Worker   jrawMonitorID mon_;
87*795d594fSAndroid Build Coastguard Worker   std::string out_fd_name_;
88*795d594fSAndroid Build Coastguard Worker   int out_fd_;
89*795d594fSAndroid Build Coastguard Worker   std::unordered_map<jmethodID, uint64_t> method_counts_;
90*795d594fSAndroid Build Coastguard Worker   bool shutdown_;
91*795d594fSAndroid Build Coastguard Worker   bool dump_on_shutdown_;
92*795d594fSAndroid Build Coastguard Worker   bool dump_on_main_stop_;
93*795d594fSAndroid Build Coastguard Worker };
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker struct ScopedJvmtiMonitor {
96*795d594fSAndroid Build Coastguard Worker  public:
ScopedJvmtiMonitorsimple_profile::ScopedJvmtiMonitor97*795d594fSAndroid Build Coastguard Worker   ScopedJvmtiMonitor(jvmtiEnv* env, jrawMonitorID mon) : jvmti_(env), mon_(mon) {
98*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(jvmti_->RawMonitorEnter(mon_));
99*795d594fSAndroid Build Coastguard Worker   }
100*795d594fSAndroid Build Coastguard Worker 
~ScopedJvmtiMonitorsimple_profile::ScopedJvmtiMonitor101*795d594fSAndroid Build Coastguard Worker   ~ScopedJvmtiMonitor() {
102*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(jvmti_->RawMonitorExit(mon_));
103*795d594fSAndroid Build Coastguard Worker   }
104*795d594fSAndroid Build Coastguard Worker 
Notifysimple_profile::ScopedJvmtiMonitor105*795d594fSAndroid Build Coastguard Worker   void Notify() {
106*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(jvmti_->RawMonitorNotifyAll(mon_));
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker 
Waitsimple_profile::ScopedJvmtiMonitor109*795d594fSAndroid Build Coastguard Worker   void Wait() {
110*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(jvmti_->RawMonitorWait(mon_, 0));
111*795d594fSAndroid Build Coastguard Worker   }
112*795d594fSAndroid Build Coastguard Worker 
113*795d594fSAndroid Build Coastguard Worker  private:
114*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* jvmti_;
115*795d594fSAndroid Build Coastguard Worker   jrawMonitorID mon_;
116*795d594fSAndroid Build Coastguard Worker };
117*795d594fSAndroid Build Coastguard Worker 
Enter(jvmtiEnv * jvmti,JNIEnv * env,jmethodID meth)118*795d594fSAndroid Build Coastguard Worker void SimpleProfileData::Enter(jvmtiEnv* jvmti, JNIEnv* env, jmethodID meth) {
119*795d594fSAndroid Build Coastguard Worker   ScopedJvmtiMonitor sjm(jvmti, mon_);
120*795d594fSAndroid Build Coastguard Worker   // Keep all classes from being unloaded to allow us to know we can get the method info later.
121*795d594fSAndroid Build Coastguard Worker   jclass tmp;
122*795d594fSAndroid Build Coastguard Worker   CHECK_JVMTI(jvmti->GetMethodDeclaringClass(meth, &tmp));
123*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jclass> klass(env, tmp);
124*795d594fSAndroid Build Coastguard Worker   jlong tag;
125*795d594fSAndroid Build Coastguard Worker   CHECK_JVMTI(jvmti->GetTag(klass.get(), &tag));
126*795d594fSAndroid Build Coastguard Worker   if (tag == 0) {
127*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(jvmti->SetTag(klass.get(), 1u));
128*795d594fSAndroid Build Coastguard Worker     env->NewGlobalRef(klass.get());
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker   method_counts_.insert({ meth, 0u }).first->second++;
131*795d594fSAndroid Build Coastguard Worker }
132*795d594fSAndroid Build Coastguard Worker 
Dump(jvmtiEnv * jvmti)133*795d594fSAndroid Build Coastguard Worker void SimpleProfileData::Dump(jvmtiEnv* jvmti) {
134*795d594fSAndroid Build Coastguard Worker   ScopedJvmtiMonitor sjm(jvmti, mon_);
135*795d594fSAndroid Build Coastguard Worker   dump_id_++;
136*795d594fSAndroid Build Coastguard Worker   sjm.Notify();
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker 
RunDumpLoop(jvmtiEnv * jvmti,JNIEnv * env)139*795d594fSAndroid Build Coastguard Worker void SimpleProfileData::RunDumpLoop(jvmtiEnv* jvmti, JNIEnv* env) {
140*795d594fSAndroid Build Coastguard Worker   jlong current_id = 0;
141*795d594fSAndroid Build Coastguard Worker   do {
142*795d594fSAndroid Build Coastguard Worker     std::unordered_map<jmethodID, uint64_t> copy;
143*795d594fSAndroid Build Coastguard Worker     {
144*795d594fSAndroid Build Coastguard Worker       ScopedJvmtiMonitor sjm(jvmti, mon_);
145*795d594fSAndroid Build Coastguard Worker       while (!shutdown_ && current_id == dump_id_) {
146*795d594fSAndroid Build Coastguard Worker         sjm.Wait();
147*795d594fSAndroid Build Coastguard Worker       }
148*795d594fSAndroid Build Coastguard Worker       if (shutdown_) {
149*795d594fSAndroid Build Coastguard Worker         break;
150*795d594fSAndroid Build Coastguard Worker       }
151*795d594fSAndroid Build Coastguard Worker       current_id = dump_id_;
152*795d594fSAndroid Build Coastguard Worker       copy = method_counts_;
153*795d594fSAndroid Build Coastguard Worker     }
154*795d594fSAndroid Build Coastguard Worker     DoDump(jvmti, env, std::move(copy));
155*795d594fSAndroid Build Coastguard Worker   } while (true);
156*795d594fSAndroid Build Coastguard Worker }
157*795d594fSAndroid Build Coastguard Worker 
Shutdown(jvmtiEnv * jvmti,JNIEnv * jni)158*795d594fSAndroid Build Coastguard Worker void SimpleProfileData::Shutdown(jvmtiEnv* jvmti, JNIEnv* jni) {
159*795d594fSAndroid Build Coastguard Worker   std::unordered_map<jmethodID, uint64_t> copy;
160*795d594fSAndroid Build Coastguard Worker   {
161*795d594fSAndroid Build Coastguard Worker     ScopedJvmtiMonitor sjm(jvmti, mon_);
162*795d594fSAndroid Build Coastguard Worker     if (shutdown_) {
163*795d594fSAndroid Build Coastguard Worker       return;
164*795d594fSAndroid Build Coastguard Worker     }
165*795d594fSAndroid Build Coastguard Worker     shutdown_ = true;
166*795d594fSAndroid Build Coastguard Worker     copy = method_counts_;
167*795d594fSAndroid Build Coastguard Worker     sjm.Notify();
168*795d594fSAndroid Build Coastguard Worker   }
169*795d594fSAndroid Build Coastguard Worker   if (dump_on_shutdown_) {
170*795d594fSAndroid Build Coastguard Worker     DoDump(jvmti, jni, std::move(copy));
171*795d594fSAndroid Build Coastguard Worker   }
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker 
FinishInitialization(jvmtiEnv * jvmti,JNIEnv * env,jthread cur)174*795d594fSAndroid Build Coastguard Worker void SimpleProfileData::FinishInitialization(jvmtiEnv* jvmti, JNIEnv* env, jthread cur) {
175*795d594fSAndroid Build Coastguard Worker   // Finish up startup.
176*795d594fSAndroid Build Coastguard Worker   // Create a Thread object.
177*795d594fSAndroid Build Coastguard Worker   std::string name = std::string("profile dump Thread: ") + this->out_fd_name_;
178*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF(name.c_str()));
179*795d594fSAndroid Build Coastguard Worker   CHECK_NE(thread_name.get(), nullptr);
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
182*795d594fSAndroid Build Coastguard Worker   CHECK_NE(thread_klass.get(), nullptr);
183*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
184*795d594fSAndroid Build Coastguard Worker   CHECK_NE(thread.get(), nullptr);
185*795d594fSAndroid Build Coastguard Worker   jmethodID initID = env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V");
186*795d594fSAndroid Build Coastguard Worker   jmethodID setDaemonId = env->GetMethodID(thread_klass.get(), "setDaemon", "(Z)V");
187*795d594fSAndroid Build Coastguard Worker   CHECK_NE(initID, nullptr);
188*795d594fSAndroid Build Coastguard Worker   CHECK_NE(setDaemonId, nullptr);
189*795d594fSAndroid Build Coastguard Worker   env->CallNonvirtualVoidMethod(thread.get(), thread_klass.get(), initID, thread_name.get());
190*795d594fSAndroid Build Coastguard Worker   env->CallVoidMethod(thread.get(), setDaemonId, JNI_TRUE);
191*795d594fSAndroid Build Coastguard Worker   CHECK(!env->ExceptionCheck());
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker   CHECK_JVMTI(jvmti->RunAgentThread(
194*795d594fSAndroid Build Coastguard Worker       thread.get(),
195*795d594fSAndroid Build Coastguard Worker       [](jvmtiEnv* jvmti, JNIEnv* jni, [[maybe_unused]] void* unused_data) {
196*795d594fSAndroid Build Coastguard Worker         SimpleProfileData* data = SimpleProfileData::GetProfileData(jvmti);
197*795d594fSAndroid Build Coastguard Worker         data->RunDumpLoop(jvmti, jni);
198*795d594fSAndroid Build Coastguard Worker       },
199*795d594fSAndroid Build Coastguard Worker       nullptr,
200*795d594fSAndroid Build Coastguard Worker       JVMTI_THREAD_NORM_PRIORITY));
201*795d594fSAndroid Build Coastguard Worker 
202*795d594fSAndroid Build Coastguard Worker   CHECK_JVMTI(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, nullptr));
203*795d594fSAndroid Build Coastguard Worker   CHECK_JVMTI(
204*795d594fSAndroid Build Coastguard Worker       jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, nullptr));
205*795d594fSAndroid Build Coastguard Worker   if (dump_on_main_stop_) {
206*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, cur));
207*795d594fSAndroid Build Coastguard Worker   }
208*795d594fSAndroid Build Coastguard Worker   CHECK_JVMTI(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, nullptr));
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker 
211*795d594fSAndroid Build Coastguard Worker class ScopedClassInfo {
212*795d594fSAndroid Build Coastguard Worker  public:
ScopedClassInfo(jvmtiEnv * jvmti_env,jclass c)213*795d594fSAndroid Build Coastguard Worker   ScopedClassInfo(jvmtiEnv* jvmti_env, jclass c)
214*795d594fSAndroid Build Coastguard Worker       : jvmti_env_(jvmti_env), class_(c), name_(nullptr), generic_(nullptr) {}
215*795d594fSAndroid Build Coastguard Worker 
~ScopedClassInfo()216*795d594fSAndroid Build Coastguard Worker   ~ScopedClassInfo() {
217*795d594fSAndroid Build Coastguard Worker     if (class_ != nullptr) {
218*795d594fSAndroid Build Coastguard Worker       jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(name_));
219*795d594fSAndroid Build Coastguard Worker       jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
220*795d594fSAndroid Build Coastguard Worker     }
221*795d594fSAndroid Build Coastguard Worker   }
222*795d594fSAndroid Build Coastguard Worker 
Init()223*795d594fSAndroid Build Coastguard Worker   bool Init() {
224*795d594fSAndroid Build Coastguard Worker     if (class_ == nullptr) {
225*795d594fSAndroid Build Coastguard Worker       name_ = const_cast<char*>("<NONE>");
226*795d594fSAndroid Build Coastguard Worker       generic_ = const_cast<char*>("<NONE>");
227*795d594fSAndroid Build Coastguard Worker       return true;
228*795d594fSAndroid Build Coastguard Worker     } else {
229*795d594fSAndroid Build Coastguard Worker       return jvmti_env_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE;
230*795d594fSAndroid Build Coastguard Worker     }
231*795d594fSAndroid Build Coastguard Worker   }
232*795d594fSAndroid Build Coastguard Worker 
GetClass() const233*795d594fSAndroid Build Coastguard Worker   jclass GetClass() const {
234*795d594fSAndroid Build Coastguard Worker     return class_;
235*795d594fSAndroid Build Coastguard Worker   }
GetName() const236*795d594fSAndroid Build Coastguard Worker   const char* GetName() const {
237*795d594fSAndroid Build Coastguard Worker     return name_;
238*795d594fSAndroid Build Coastguard Worker   }
239*795d594fSAndroid Build Coastguard Worker   // Generic type parameters, whatever is in the <> for a class
GetGeneric() const240*795d594fSAndroid Build Coastguard Worker   const char* GetGeneric() const {
241*795d594fSAndroid Build Coastguard Worker     return generic_;
242*795d594fSAndroid Build Coastguard Worker   }
243*795d594fSAndroid Build Coastguard Worker 
244*795d594fSAndroid Build Coastguard Worker  private:
245*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* jvmti_env_;
246*795d594fSAndroid Build Coastguard Worker   jclass class_;
247*795d594fSAndroid Build Coastguard Worker   char* name_;
248*795d594fSAndroid Build Coastguard Worker   char* generic_;
249*795d594fSAndroid Build Coastguard Worker };
250*795d594fSAndroid Build Coastguard Worker 
251*795d594fSAndroid Build Coastguard Worker class ScopedMethodInfo {
252*795d594fSAndroid Build Coastguard Worker  public:
ScopedMethodInfo(jvmtiEnv * jvmti_env,JNIEnv * env,jmethodID method)253*795d594fSAndroid Build Coastguard Worker   ScopedMethodInfo(jvmtiEnv* jvmti_env, JNIEnv* env, jmethodID method)
254*795d594fSAndroid Build Coastguard Worker       : jvmti_env_(jvmti_env),
255*795d594fSAndroid Build Coastguard Worker         env_(env),
256*795d594fSAndroid Build Coastguard Worker         method_(method),
257*795d594fSAndroid Build Coastguard Worker         declaring_class_(nullptr),
258*795d594fSAndroid Build Coastguard Worker         class_info_(nullptr),
259*795d594fSAndroid Build Coastguard Worker         name_(nullptr),
260*795d594fSAndroid Build Coastguard Worker         signature_(nullptr),
261*795d594fSAndroid Build Coastguard Worker         generic_(nullptr) {}
262*795d594fSAndroid Build Coastguard Worker 
~ScopedMethodInfo()263*795d594fSAndroid Build Coastguard Worker   ~ScopedMethodInfo() {
264*795d594fSAndroid Build Coastguard Worker     env_->DeleteLocalRef(declaring_class_);
265*795d594fSAndroid Build Coastguard Worker     jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(name_));
266*795d594fSAndroid Build Coastguard Worker     jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
267*795d594fSAndroid Build Coastguard Worker     jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
268*795d594fSAndroid Build Coastguard Worker   }
269*795d594fSAndroid Build Coastguard Worker 
Init()270*795d594fSAndroid Build Coastguard Worker   bool Init() {
271*795d594fSAndroid Build Coastguard Worker     if (jvmti_env_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
272*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "No decl";
273*795d594fSAndroid Build Coastguard Worker       return false;
274*795d594fSAndroid Build Coastguard Worker     }
275*795d594fSAndroid Build Coastguard Worker     class_info_.reset(new ScopedClassInfo(jvmti_env_, declaring_class_));
276*795d594fSAndroid Build Coastguard Worker     return class_info_->Init() &&
277*795d594fSAndroid Build Coastguard Worker            (jvmti_env_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
278*795d594fSAndroid Build Coastguard Worker   }
279*795d594fSAndroid Build Coastguard Worker 
GetDeclaringClassInfo() const280*795d594fSAndroid Build Coastguard Worker   const ScopedClassInfo& GetDeclaringClassInfo() const {
281*795d594fSAndroid Build Coastguard Worker     return *class_info_;
282*795d594fSAndroid Build Coastguard Worker   }
283*795d594fSAndroid Build Coastguard Worker 
GetDeclaringClass() const284*795d594fSAndroid Build Coastguard Worker   jclass GetDeclaringClass() const {
285*795d594fSAndroid Build Coastguard Worker     return declaring_class_;
286*795d594fSAndroid Build Coastguard Worker   }
287*795d594fSAndroid Build Coastguard Worker 
GetName() const288*795d594fSAndroid Build Coastguard Worker   const char* GetName() const {
289*795d594fSAndroid Build Coastguard Worker     return name_;
290*795d594fSAndroid Build Coastguard Worker   }
291*795d594fSAndroid Build Coastguard Worker 
GetSignature() const292*795d594fSAndroid Build Coastguard Worker   const char* GetSignature() const {
293*795d594fSAndroid Build Coastguard Worker     return signature_;
294*795d594fSAndroid Build Coastguard Worker   }
295*795d594fSAndroid Build Coastguard Worker 
GetGeneric() const296*795d594fSAndroid Build Coastguard Worker   const char* GetGeneric() const {
297*795d594fSAndroid Build Coastguard Worker     return generic_;
298*795d594fSAndroid Build Coastguard Worker   }
299*795d594fSAndroid Build Coastguard Worker 
300*795d594fSAndroid Build Coastguard Worker  private:
301*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* jvmti_env_;
302*795d594fSAndroid Build Coastguard Worker   JNIEnv* env_;
303*795d594fSAndroid Build Coastguard Worker   jmethodID method_;
304*795d594fSAndroid Build Coastguard Worker   jclass declaring_class_;
305*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ScopedClassInfo> class_info_;
306*795d594fSAndroid Build Coastguard Worker   char* name_;
307*795d594fSAndroid Build Coastguard Worker   char* signature_;
308*795d594fSAndroid Build Coastguard Worker   char* generic_;
309*795d594fSAndroid Build Coastguard Worker 
310*795d594fSAndroid Build Coastguard Worker   friend std::ostream& operator<<(std::ostream& os, ScopedMethodInfo const& method);
311*795d594fSAndroid Build Coastguard Worker };
312*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const ScopedMethodInfo * method)313*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const ScopedMethodInfo* method) {
314*795d594fSAndroid Build Coastguard Worker   return os << *method;
315*795d594fSAndroid Build Coastguard Worker }
316*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,ScopedMethodInfo const & method)317*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ScopedMethodInfo const& method) {
318*795d594fSAndroid Build Coastguard Worker   return os << method.GetDeclaringClassInfo().GetName() << "->" << method.GetName()
319*795d594fSAndroid Build Coastguard Worker             << method.GetSignature();
320*795d594fSAndroid Build Coastguard Worker }
321*795d594fSAndroid Build Coastguard Worker 
DoDump(jvmtiEnv * jvmti,JNIEnv * jni,const std::unordered_map<jmethodID,uint64_t> & copy)322*795d594fSAndroid Build Coastguard Worker void SimpleProfileData::DoDump(jvmtiEnv* jvmti,
323*795d594fSAndroid Build Coastguard Worker                                JNIEnv* jni,
324*795d594fSAndroid Build Coastguard Worker                                const std::unordered_map<jmethodID, uint64_t>& copy) {
325*795d594fSAndroid Build Coastguard Worker   std::ostringstream oss;
326*795d594fSAndroid Build Coastguard Worker   oss << "[";
327*795d594fSAndroid Build Coastguard Worker   bool is_first = true;
328*795d594fSAndroid Build Coastguard Worker   for (auto [meth, cnt] : copy) {
329*795d594fSAndroid Build Coastguard Worker     ScopedMethodInfo smi(jvmti, jni, meth);
330*795d594fSAndroid Build Coastguard Worker     if (!smi.Init()) {
331*795d594fSAndroid Build Coastguard Worker       continue;
332*795d594fSAndroid Build Coastguard Worker     }
333*795d594fSAndroid Build Coastguard Worker     if (!is_first) {
334*795d594fSAndroid Build Coastguard Worker       oss << "," << std::endl;
335*795d594fSAndroid Build Coastguard Worker     }
336*795d594fSAndroid Build Coastguard Worker     is_first = false;
337*795d594fSAndroid Build Coastguard Worker     oss << DataDefinition {
338*795d594fSAndroid Build Coastguard Worker       .class_name = smi.GetDeclaringClassInfo().GetName(),
339*795d594fSAndroid Build Coastguard Worker       .method_name = smi.GetName(),
340*795d594fSAndroid Build Coastguard Worker       .method_descriptor = smi.GetSignature(),
341*795d594fSAndroid Build Coastguard Worker       .count = cnt,
342*795d594fSAndroid Build Coastguard Worker     };
343*795d594fSAndroid Build Coastguard Worker   }
344*795d594fSAndroid Build Coastguard Worker   oss << "]";
345*795d594fSAndroid Build Coastguard Worker   CHECK_GE(TEMP_FAILURE_RETRY(write(out_fd_, oss.str().c_str(), oss.str().size())), 0)
346*795d594fSAndroid Build Coastguard Worker       << strerror(errno) << out_fd_ << " " << out_fd_name_;
347*795d594fSAndroid Build Coastguard Worker   fsync(out_fd_);
348*795d594fSAndroid Build Coastguard Worker }
349*795d594fSAndroid Build Coastguard Worker 
DataDumpCb(jvmtiEnv * jvmti_env)350*795d594fSAndroid Build Coastguard Worker static void DataDumpCb(jvmtiEnv* jvmti_env) {
351*795d594fSAndroid Build Coastguard Worker   SimpleProfileData* data = SimpleProfileData::GetProfileData(jvmti_env);
352*795d594fSAndroid Build Coastguard Worker   data->Dump(jvmti_env);
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker 
MethodEntryCB(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread,jmethodID method)355*795d594fSAndroid Build Coastguard Worker static void MethodEntryCB(jvmtiEnv* jvmti_env,
356*795d594fSAndroid Build Coastguard Worker                           JNIEnv* env,
357*795d594fSAndroid Build Coastguard Worker                           [[maybe_unused]] jthread thread,
358*795d594fSAndroid Build Coastguard Worker                           jmethodID method) {
359*795d594fSAndroid Build Coastguard Worker   SimpleProfileData* data = SimpleProfileData::GetProfileData(jvmti_env);
360*795d594fSAndroid Build Coastguard Worker   data->Enter(jvmti_env, env, method);
361*795d594fSAndroid Build Coastguard Worker }
362*795d594fSAndroid Build Coastguard Worker 
VMInitCB(jvmtiEnv * jvmti,JNIEnv * env,jthread thr)363*795d594fSAndroid Build Coastguard Worker static void VMInitCB(jvmtiEnv* jvmti, JNIEnv* env, jthread thr) {
364*795d594fSAndroid Build Coastguard Worker   SimpleProfileData* data = SimpleProfileData::GetProfileData(jvmti);
365*795d594fSAndroid Build Coastguard Worker   data->FinishInitialization(jvmti, env, thr);
366*795d594fSAndroid Build Coastguard Worker }
VMDeathCB(jvmtiEnv * jvmti,JNIEnv * env)367*795d594fSAndroid Build Coastguard Worker static void VMDeathCB(jvmtiEnv* jvmti, JNIEnv* env) {
368*795d594fSAndroid Build Coastguard Worker   SimpleProfileData* data = SimpleProfileData::GetProfileData(jvmti);
369*795d594fSAndroid Build Coastguard Worker   data->Shutdown(jvmti, env);
370*795d594fSAndroid Build Coastguard Worker }
371*795d594fSAndroid Build Coastguard Worker 
372*795d594fSAndroid Build Coastguard Worker // Fills targets with the breakpoints to add.
373*795d594fSAndroid Build Coastguard Worker // Lname/of/Klass;->methodName(Lsig/of/Method)Lreturn/Type;@location,<...>
ParseArgs(const std::string & start_options,std::string * fd_name,int * fd,bool * dump_on_shutdown,bool * dump_on_main_stop)374*795d594fSAndroid Build Coastguard Worker static bool ParseArgs(const std::string& start_options,
375*795d594fSAndroid Build Coastguard Worker                       /*out*/ std::string* fd_name,
376*795d594fSAndroid Build Coastguard Worker                       /*out*/ int* fd,
377*795d594fSAndroid Build Coastguard Worker                       /*out*/ bool* dump_on_shutdown,
378*795d594fSAndroid Build Coastguard Worker                       /*out*/ bool* dump_on_main_stop) {
379*795d594fSAndroid Build Coastguard Worker   std::istringstream iss(start_options);
380*795d594fSAndroid Build Coastguard Worker   std::string item;
381*795d594fSAndroid Build Coastguard Worker   *dump_on_main_stop = false;
382*795d594fSAndroid Build Coastguard Worker   *dump_on_shutdown = false;
383*795d594fSAndroid Build Coastguard Worker   bool has_fd = false;
384*795d594fSAndroid Build Coastguard Worker   while (std::getline(iss, item, ',')) {
385*795d594fSAndroid Build Coastguard Worker     if (item == "dump_on_shutdown") {
386*795d594fSAndroid Build Coastguard Worker       *dump_on_shutdown = true;
387*795d594fSAndroid Build Coastguard Worker     } else if (item == "dump_on_main_stop") {
388*795d594fSAndroid Build Coastguard Worker       *dump_on_main_stop = true;
389*795d594fSAndroid Build Coastguard Worker     } else if (has_fd) {
390*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Too many args!";
391*795d594fSAndroid Build Coastguard Worker       return false;
392*795d594fSAndroid Build Coastguard Worker     } else {
393*795d594fSAndroid Build Coastguard Worker       has_fd = true;
394*795d594fSAndroid Build Coastguard Worker       *fd_name = item;
395*795d594fSAndroid Build Coastguard Worker       *fd = TEMP_FAILURE_RETRY(open(fd_name->c_str(), O_WRONLY | O_CLOEXEC | O_CREAT, 00666));
396*795d594fSAndroid Build Coastguard Worker       CHECK_GE(*fd, 0) << strerror(errno);
397*795d594fSAndroid Build Coastguard Worker     }
398*795d594fSAndroid Build Coastguard Worker   }
399*795d594fSAndroid Build Coastguard Worker   return has_fd;
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker 
402*795d594fSAndroid Build Coastguard Worker enum class StartType {
403*795d594fSAndroid Build Coastguard Worker   OnAttach,
404*795d594fSAndroid Build Coastguard Worker   OnLoad,
405*795d594fSAndroid Build Coastguard Worker };
406*795d594fSAndroid Build Coastguard Worker 
SetupJvmtiEnv(JavaVM * vm,jvmtiEnv ** jvmti)407*795d594fSAndroid Build Coastguard Worker static jint SetupJvmtiEnv(JavaVM* vm, jvmtiEnv** jvmti) {
408*795d594fSAndroid Build Coastguard Worker   jint res = 0;
409*795d594fSAndroid Build Coastguard Worker   res = vm->GetEnv(reinterpret_cast<void**>(jvmti), JVMTI_VERSION_1_1);
410*795d594fSAndroid Build Coastguard Worker 
411*795d594fSAndroid Build Coastguard Worker   if (res != JNI_OK || *jvmti == nullptr) {
412*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to access JVMTI, error code " << res;
413*795d594fSAndroid Build Coastguard Worker     return vm->GetEnv(reinterpret_cast<void**>(jvmti), kArtTiVersion);
414*795d594fSAndroid Build Coastguard Worker   }
415*795d594fSAndroid Build Coastguard Worker   return res;
416*795d594fSAndroid Build Coastguard Worker }
417*795d594fSAndroid Build Coastguard Worker 
AgentStart(StartType start,JavaVM * vm,const char * options,void * reserved)418*795d594fSAndroid Build Coastguard Worker static jint AgentStart(StartType start,
419*795d594fSAndroid Build Coastguard Worker                        JavaVM* vm,
420*795d594fSAndroid Build Coastguard Worker                        const char* options,
421*795d594fSAndroid Build Coastguard Worker                        [[maybe_unused]] void* reserved) {
422*795d594fSAndroid Build Coastguard Worker   if (options == nullptr) {
423*795d594fSAndroid Build Coastguard Worker     options = "";
424*795d594fSAndroid Build Coastguard Worker   }
425*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* jvmti = nullptr;
426*795d594fSAndroid Build Coastguard Worker   jvmtiError error = JVMTI_ERROR_NONE;
427*795d594fSAndroid Build Coastguard Worker   {
428*795d594fSAndroid Build Coastguard Worker     jint res = 0;
429*795d594fSAndroid Build Coastguard Worker     res = SetupJvmtiEnv(vm, &jvmti);
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker     if (res != JNI_OK || jvmti == nullptr) {
432*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Unable to access JVMTI, error code " << res;
433*795d594fSAndroid Build Coastguard Worker       return JNI_ERR;
434*795d594fSAndroid Build Coastguard Worker     }
435*795d594fSAndroid Build Coastguard Worker   }
436*795d594fSAndroid Build Coastguard Worker 
437*795d594fSAndroid Build Coastguard Worker   int fd;
438*795d594fSAndroid Build Coastguard Worker   std::string fd_name;
439*795d594fSAndroid Build Coastguard Worker   bool dump_on_shutdown;
440*795d594fSAndroid Build Coastguard Worker   bool dump_on_main_stop;
441*795d594fSAndroid Build Coastguard Worker   if (!ParseArgs(options,
442*795d594fSAndroid Build Coastguard Worker                  /*out*/ &fd_name,
443*795d594fSAndroid Build Coastguard Worker                  /*out*/ &fd,
444*795d594fSAndroid Build Coastguard Worker                  /*out*/ &dump_on_shutdown,
445*795d594fSAndroid Build Coastguard Worker                  /*out*/ &dump_on_main_stop)) {
446*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "failed to get output file from " << options << "!";
447*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
448*795d594fSAndroid Build Coastguard Worker   }
449*795d594fSAndroid Build Coastguard Worker 
450*795d594fSAndroid Build Coastguard Worker   void* data_mem = nullptr;
451*795d594fSAndroid Build Coastguard Worker   error = jvmti->Allocate(sizeof(SimpleProfileData), reinterpret_cast<unsigned char**>(&data_mem));
452*795d594fSAndroid Build Coastguard Worker   if (error != JVMTI_ERROR_NONE) {
453*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to alloc memory for breakpoint target data";
454*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
455*795d594fSAndroid Build Coastguard Worker   }
456*795d594fSAndroid Build Coastguard Worker 
457*795d594fSAndroid Build Coastguard Worker   SimpleProfileData* data =
458*795d594fSAndroid Build Coastguard Worker       new (data_mem) SimpleProfileData(jvmti, fd_name, fd, dump_on_shutdown, dump_on_main_stop);
459*795d594fSAndroid Build Coastguard Worker   error = jvmti->SetEnvironmentLocalStorage(data);
460*795d594fSAndroid Build Coastguard Worker   if (error != JVMTI_ERROR_NONE) {
461*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to set local storage";
462*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
463*795d594fSAndroid Build Coastguard Worker   }
464*795d594fSAndroid Build Coastguard Worker 
465*795d594fSAndroid Build Coastguard Worker   jvmtiCapabilities caps {};
466*795d594fSAndroid Build Coastguard Worker   caps.can_generate_method_entry_events = JNI_TRUE;
467*795d594fSAndroid Build Coastguard Worker   caps.can_tag_objects = JNI_TRUE;
468*795d594fSAndroid Build Coastguard Worker   error = jvmti->AddCapabilities(&caps);
469*795d594fSAndroid Build Coastguard Worker   if (error != JVMTI_ERROR_NONE) {
470*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to set caps";
471*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
472*795d594fSAndroid Build Coastguard Worker   }
473*795d594fSAndroid Build Coastguard Worker 
474*795d594fSAndroid Build Coastguard Worker   jvmtiEventCallbacks callbacks {};
475*795d594fSAndroid Build Coastguard Worker   callbacks.MethodEntry = &MethodEntryCB;
476*795d594fSAndroid Build Coastguard Worker   callbacks.VMInit = &VMInitCB;
477*795d594fSAndroid Build Coastguard Worker   callbacks.DataDumpRequest = &DataDumpCb;
478*795d594fSAndroid Build Coastguard Worker   callbacks.VMDeath = &VMDeathCB;
479*795d594fSAndroid Build Coastguard Worker   callbacks.ThreadEnd = [](jvmtiEnv* env, JNIEnv* jni, [[maybe_unused]] jthread thr) {
480*795d594fSAndroid Build Coastguard Worker     VMDeathCB(env, jni);
481*795d594fSAndroid Build Coastguard Worker   };
482*795d594fSAndroid Build Coastguard Worker 
483*795d594fSAndroid Build Coastguard Worker   error = jvmti->SetEventCallbacks(&callbacks, static_cast<jint>(sizeof(callbacks)));
484*795d594fSAndroid Build Coastguard Worker 
485*795d594fSAndroid Build Coastguard Worker   if (error != JVMTI_ERROR_NONE) {
486*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to set event callbacks.";
487*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
488*795d594fSAndroid Build Coastguard Worker   }
489*795d594fSAndroid Build Coastguard Worker 
490*795d594fSAndroid Build Coastguard Worker   if (start == StartType::OnAttach) {
491*795d594fSAndroid Build Coastguard Worker     JNIEnv* env = nullptr;
492*795d594fSAndroid Build Coastguard Worker     jint res = 0;
493*795d594fSAndroid Build Coastguard Worker     res = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_2);
494*795d594fSAndroid Build Coastguard Worker     if (res != JNI_OK || env == nullptr) {
495*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Unable to get jnienv";
496*795d594fSAndroid Build Coastguard Worker       return JNI_ERR;
497*795d594fSAndroid Build Coastguard Worker     }
498*795d594fSAndroid Build Coastguard Worker     jthread temp;
499*795d594fSAndroid Build Coastguard Worker     ScopedLocalRef<jthread> cur(env, nullptr);
500*795d594fSAndroid Build Coastguard Worker     CHECK_JVMTI(jvmti->GetCurrentThread(&temp));
501*795d594fSAndroid Build Coastguard Worker     cur.reset(temp);
502*795d594fSAndroid Build Coastguard Worker     VMInitCB(jvmti, env, cur.get());
503*795d594fSAndroid Build Coastguard Worker   } else {
504*795d594fSAndroid Build Coastguard Worker     error = jvmti->SetEventNotificationMode(
505*795d594fSAndroid Build Coastguard Worker         JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, nullptr /* all threads */);
506*795d594fSAndroid Build Coastguard Worker     if (error != JVMTI_ERROR_NONE) {
507*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Unable to set event vminit";
508*795d594fSAndroid Build Coastguard Worker       return JNI_ERR;
509*795d594fSAndroid Build Coastguard Worker     }
510*795d594fSAndroid Build Coastguard Worker   }
511*795d594fSAndroid Build Coastguard Worker   return JNI_OK;
512*795d594fSAndroid Build Coastguard Worker }
513*795d594fSAndroid Build Coastguard Worker 
514*795d594fSAndroid Build Coastguard Worker // Late attachment (e.g. 'am attach-agent').
Agent_OnAttach(JavaVM * vm,char * options,void * reserved)515*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
516*795d594fSAndroid Build Coastguard Worker   return AgentStart(StartType::OnAttach, vm, options, reserved);
517*795d594fSAndroid Build Coastguard Worker }
518*795d594fSAndroid Build Coastguard Worker 
519*795d594fSAndroid Build Coastguard Worker // Early attachment
Agent_OnLoad(JavaVM * jvm,char * options,void * reserved)520*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) {
521*795d594fSAndroid Build Coastguard Worker   return AgentStart(StartType::OnLoad, jvm, options, reserved);
522*795d594fSAndroid Build Coastguard Worker }
523*795d594fSAndroid Build Coastguard Worker 
524*795d594fSAndroid Build Coastguard Worker }  // namespace simple_profile
525