Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: base/android/java/src/org/chromium/base/EarlyTraceEvent.java

Issue 2165583002: Reland 2: Android: Add support for TraceEvent before the native library is loaded. (patchset #2 id:… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add the GYP changes back, as they're still needed by WebRTC. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 package org.chromium.base;
6
7 import android.os.Process;
8 import android.os.StrictMode;
9 import android.os.SystemClock;
10
11 import org.chromium.base.annotations.JNINamespace;
12 import org.chromium.base.annotations.SuppressFBWarnings;
13
14 import java.io.File;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19
20 /** Support for early tracing, before the native library is loaded.
21 *
22 * This is limited, as:
23 * - Arguments are not supported
24 * - Thread time is not reported
25 * - Two events with the same name cannot be in progress at the same time.
26 *
27 * Events recorded here are buffered in Java until the native library is availab le. Then it waits
28 * for the completion of pending events, and sends the events to the native side .
29 *
30 * Locking: This class is threadsafe. It is enabled when general tracing is, and then disabled when
31 * tracing is enabled from the native side. Event completions are still processed as long
32 * as some are pending, then early tracing is permanently disabled afte r dumping the
33 * events. This means that if any early event is still pending when tr acing is disabled,
34 * all early events are dropped.
35 */
36 @JNINamespace("base::android")
37 public class EarlyTraceEvent {
38 // Must be kept in sync with the native kAndroidTraceConfigFile.
39 private static final String TRACE_CONFIG_FILENAME = "/data/local/chrome-trac e-config.json";
40
41 /** Single trace event. */
42 @VisibleForTesting
43 static final class Event {
44 final String mName;
45 final int mThreadId;
46 final long mBeginTimeMs;
47 long mEndTimeMs;
48
49 Event(String name) {
50 mName = name;
51 mThreadId = Process.myTid();
52 mBeginTimeMs = SystemClock.elapsedRealtime();
53 }
54
55 void end() {
56 assert mEndTimeMs == 0;
57 mEndTimeMs = SystemClock.elapsedRealtime();
58 }
59 }
60
61 // State transitions are:
62 // - enable(): DISABLED -> ENABLED
63 // - disable(): ENABLED -> FINISHING
64 // - Once there are no pending events: FINISHING -> FINISHED.
65 @VisibleForTesting static final int STATE_DISABLED = 0;
66 @VisibleForTesting static final int STATE_ENABLED = 1;
67 @VisibleForTesting static final int STATE_FINISHING = 2;
68 @VisibleForTesting static final int STATE_FINISHED = 3;
69
70 // Locks the fields below.
71 private static final Object sLock = new Object();
72
73 @VisibleForTesting static volatile int sState = STATE_DISABLED;
74 // Not final as these object are not likely to be used at all.
75 @VisibleForTesting static List<Event> sCompletedEvents;
76 @VisibleForTesting static Map<String, Event> sPendingEvents;
77
78 /** @see TraceEvent#MaybeEnableEarlyTracing().
79 */
80 @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
81 static void maybeEnable() {
82 boolean shouldEnable = false;
83 // Checking for the trace config filename touches the disk.
84 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
85 try {
86 if (CommandLine.isInitialized()
87 && CommandLine.getInstance().hasSwitch("trace-startup")) {
88 shouldEnable = true;
89 } else {
90 try {
91 shouldEnable = (new File(TRACE_CONFIG_FILENAME)).exists();
92 } catch (SecurityException e) {
93 // Access denied, not enabled.
94 }
95 }
96 } finally {
97 StrictMode.setThreadPolicy(oldPolicy);
98 }
99 if (shouldEnable) enable();
100 }
101
102 @VisibleForTesting
103 static void enable() {
104 synchronized (sLock) {
105 if (sState != STATE_DISABLED) return;
106 sCompletedEvents = new ArrayList<Event>();
107 sPendingEvents = new HashMap<String, Event>();
108 sState = STATE_ENABLED;
109 }
110 }
111
112 /**
113 * Disables Early tracing.
114 *
115 * Once this is called, no new event will be registered. However, end() call s are still recorded
116 * as long as there are pending events. Once there are none left, pass the e vents to the native
117 * side.
118 */
119 static void disable() {
120 synchronized (sLock) {
121 if (sState != STATE_ENABLED) return;
122 sState = STATE_FINISHING;
123 maybeFinishLocked();
124 }
125 }
126
127 /** @see {@link TraceEvent#begin()}. */
128 public static void begin(String name) {
129 // begin() and end() are going to be called once per TraceEvent, this av oids entering a
130 // synchronized block at each and every call.
131 if (sState != STATE_ENABLED) return;
132 Event event = new Event(name);
133 Event conflictingEvent;
134 synchronized (sLock) {
135 if (sState != STATE_ENABLED) return;
136 conflictingEvent = sPendingEvents.put(name, event);
137 }
138 if (conflictingEvent != null) {
139 throw new IllegalArgumentException(
140 "Multiple pending trace events can't have the same name");
141 }
142 }
143
144 /** @see {@link TraceEvent#end()}. */
145 public static void end(String name) {
146 int state = sState;
147 if (state != STATE_ENABLED && state != STATE_FINISHING) return;
148 synchronized (sLock) {
149 if (sState != STATE_ENABLED && sState != STATE_FINISHING) return;
150 Event event = sPendingEvents.remove(name);
151 if (event == null) return;
152 event.end();
153 sCompletedEvents.add(event);
154 if (sState == STATE_FINISHING) maybeFinishLocked();
155 }
156 }
157
158 private static void maybeFinishLocked() {
159 if (!sPendingEvents.isEmpty()) return;
160 sState = STATE_FINISHED;
161 dumpEvents(sCompletedEvents);
162 sCompletedEvents = null;
163 sPendingEvents = null;
164 }
165
166 private static void dumpEvents(List<Event> events) {
167 long nativeNowUs = nativeGetTimeTicksNowUs();
168 long javaNowUs = SystemClock.elapsedRealtime() * 1000;
169 long offsetMs = (nativeNowUs - javaNowUs) / 1000;
170 for (Event event : events) {
171 nativeRecordEarlyEvent(event.mName, event.mBeginTimeMs + offsetMs,
172 event.mEndTimeMs + offsetMs, event.mThreadId);
173 }
174 }
175
176 private static native long nativeGetTimeTicksNowUs();
177 private static native void nativeRecordEarlyEvent(
178 String name, long beginTimeMs, long endTimeMs, int threadId);
179 }
OLDNEW
« no previous file with comments | « base/android/early_trace_event_binding.cc ('k') | base/android/java/src/org/chromium/base/TraceEvent.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698