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