1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <jni.h>
6 
7 #include <set>
8 
9 #include "base/android/jni_string.h"
10 #include "base/lazy_instance.h"
11 #include "base/macros.h"
12 #include "base/trace_event/trace_event.h"
13 #include "base/trace_event/trace_event_impl.h"
14 #include "jni/TraceEvent_jni.h"
15 
16 namespace base {
17 namespace android {
18 
19 namespace {
20 
21 const char kJavaCategory[] = "Java";
22 const char kToplevelCategory[] = "toplevel";
23 const char kLooperDispatchMessage[] = "Looper.dispatchMessage";
24 
25 // Boilerplate for safely converting Java data to TRACE_EVENT data.
26 class TraceEventDataConverter {
27  public:
TraceEventDataConverter(JNIEnv * env,jstring jname,jstring jarg)28   TraceEventDataConverter(JNIEnv* env, jstring jname, jstring jarg)
29       : name_(ConvertJavaStringToUTF8(env, jname)),
30         has_arg_(jarg != nullptr),
31         arg_(jarg ? ConvertJavaStringToUTF8(env, jarg) : "") {}
~TraceEventDataConverter()32   ~TraceEventDataConverter() {
33   }
34 
35   // Return saves values to pass to TRACE_EVENT macros.
name()36   const char* name() { return name_.c_str(); }
arg_name()37   const char* arg_name() { return has_arg_ ? "arg" : nullptr; }
arg()38   const char* arg() { return has_arg_ ? arg_.c_str() : nullptr; }
39 
40  private:
41   std::string name_;
42   bool has_arg_;
43   std::string arg_;
44 
45   DISALLOW_COPY_AND_ASSIGN(TraceEventDataConverter);
46 };
47 
48 class TraceEnabledObserver
49     : public trace_event::TraceLog::EnabledStateObserver {
50   public:
OnTraceLogEnabled()51    void OnTraceLogEnabled() override {
52       JNIEnv* env = base::android::AttachCurrentThread();
53       base::android::Java_TraceEvent_setEnabled(env, true);
54     }
OnTraceLogDisabled()55     void OnTraceLogDisabled() override {
56       JNIEnv* env = base::android::AttachCurrentThread();
57       base::android::Java_TraceEvent_setEnabled(env, false);
58     }
59 };
60 
61 base::LazyInstance<TraceEnabledObserver>::Leaky g_trace_enabled_state_observer_;
62 
63 }  // namespace
64 
JNI_TraceEvent_RegisterEnabledObserver(JNIEnv * env,const JavaParamRef<jclass> & clazz)65 static void JNI_TraceEvent_RegisterEnabledObserver(
66     JNIEnv* env,
67     const JavaParamRef<jclass>& clazz) {
68   bool enabled = trace_event::TraceLog::GetInstance()->IsEnabled();
69   base::android::Java_TraceEvent_setEnabled(env, enabled);
70   trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(
71       g_trace_enabled_state_observer_.Pointer());
72 }
73 
JNI_TraceEvent_StartATrace(JNIEnv * env,const JavaParamRef<jclass> & clazz)74 static void JNI_TraceEvent_StartATrace(JNIEnv* env,
75                                        const JavaParamRef<jclass>& clazz) {
76   base::trace_event::TraceLog::GetInstance()->StartATrace();
77 }
78 
JNI_TraceEvent_StopATrace(JNIEnv * env,const JavaParamRef<jclass> & clazz)79 static void JNI_TraceEvent_StopATrace(JNIEnv* env,
80                                       const JavaParamRef<jclass>& clazz) {
81   base::trace_event::TraceLog::GetInstance()->StopATrace();
82 }
83 
JNI_TraceEvent_Instant(JNIEnv * env,const JavaParamRef<jclass> & clazz,const JavaParamRef<jstring> & jname,const JavaParamRef<jstring> & jarg)84 static void JNI_TraceEvent_Instant(JNIEnv* env,
85                                    const JavaParamRef<jclass>& clazz,
86                                    const JavaParamRef<jstring>& jname,
87                                    const JavaParamRef<jstring>& jarg) {
88   TraceEventDataConverter converter(env, jname, jarg);
89   if (converter.arg()) {
90     TRACE_EVENT_COPY_INSTANT1(kJavaCategory, converter.name(),
91                               TRACE_EVENT_SCOPE_THREAD,
92                               converter.arg_name(), converter.arg());
93   } else {
94     TRACE_EVENT_COPY_INSTANT0(kJavaCategory, converter.name(),
95                               TRACE_EVENT_SCOPE_THREAD);
96   }
97 }
98 
JNI_TraceEvent_Begin(JNIEnv * env,const JavaParamRef<jclass> & clazz,const JavaParamRef<jstring> & jname,const JavaParamRef<jstring> & jarg)99 static void JNI_TraceEvent_Begin(JNIEnv* env,
100                                  const JavaParamRef<jclass>& clazz,
101                                  const JavaParamRef<jstring>& jname,
102                                  const JavaParamRef<jstring>& jarg) {
103   TraceEventDataConverter converter(env, jname, jarg);
104   if (converter.arg()) {
105     TRACE_EVENT_COPY_BEGIN1(kJavaCategory, converter.name(),
106                        converter.arg_name(), converter.arg());
107   } else {
108     TRACE_EVENT_COPY_BEGIN0(kJavaCategory, converter.name());
109   }
110 }
111 
JNI_TraceEvent_End(JNIEnv * env,const JavaParamRef<jclass> & clazz,const JavaParamRef<jstring> & jname,const JavaParamRef<jstring> & jarg)112 static void JNI_TraceEvent_End(JNIEnv* env,
113                                const JavaParamRef<jclass>& clazz,
114                                const JavaParamRef<jstring>& jname,
115                                const JavaParamRef<jstring>& jarg) {
116   TraceEventDataConverter converter(env, jname, jarg);
117   if (converter.arg()) {
118     TRACE_EVENT_COPY_END1(kJavaCategory, converter.name(),
119                      converter.arg_name(), converter.arg());
120   } else {
121     TRACE_EVENT_COPY_END0(kJavaCategory, converter.name());
122   }
123 }
124 
JNI_TraceEvent_BeginToplevel(JNIEnv * env,const JavaParamRef<jclass> & clazz,const JavaParamRef<jstring> & jtarget)125 static void JNI_TraceEvent_BeginToplevel(JNIEnv* env,
126                                          const JavaParamRef<jclass>& clazz,
127                                          const JavaParamRef<jstring>& jtarget) {
128   std::string target = ConvertJavaStringToUTF8(env, jtarget);
129   TRACE_EVENT_BEGIN1(kToplevelCategory, kLooperDispatchMessage, "target",
130                      target);
131 }
132 
JNI_TraceEvent_EndToplevel(JNIEnv * env,const JavaParamRef<jclass> & clazz)133 static void JNI_TraceEvent_EndToplevel(JNIEnv* env,
134                                        const JavaParamRef<jclass>& clazz) {
135   TRACE_EVENT_END0(kToplevelCategory, kLooperDispatchMessage);
136 }
137 
JNI_TraceEvent_StartAsync(JNIEnv * env,const JavaParamRef<jclass> & clazz,const JavaParamRef<jstring> & jname,jlong jid)138 static void JNI_TraceEvent_StartAsync(JNIEnv* env,
139                                       const JavaParamRef<jclass>& clazz,
140                                       const JavaParamRef<jstring>& jname,
141                                       jlong jid) {
142   TraceEventDataConverter converter(env, jname, nullptr);
143   TRACE_EVENT_COPY_ASYNC_BEGIN0(kJavaCategory, converter.name(), jid);
144 }
145 
JNI_TraceEvent_FinishAsync(JNIEnv * env,const JavaParamRef<jclass> & clazz,const JavaParamRef<jstring> & jname,jlong jid)146 static void JNI_TraceEvent_FinishAsync(JNIEnv* env,
147                                        const JavaParamRef<jclass>& clazz,
148                                        const JavaParamRef<jstring>& jname,
149                                        jlong jid) {
150   TraceEventDataConverter converter(env, jname, nullptr);
151   TRACE_EVENT_COPY_ASYNC_END0(kJavaCategory, converter.name(), jid);
152 }
153 
154 }  // namespace android
155 }  // namespace base
156