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

Unified Diff: base/android/java/src/org/chromium/base/EarlyTraceEvent.java

Issue 1486053003: Android: Add support for TraceEvent before the native library is loaded. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase + fix test. 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/android/java/src/org/chromium/base/EarlyTraceEvent.java
diff --git a/base/android/java/src/org/chromium/base/EarlyTraceEvent.java b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9bd7967f86f2dfd8eaaf05b1d6ba44018def780
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
@@ -0,0 +1,179 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.SystemClock;
+
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.SuppressFBWarnings;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Support for early tracing, before the native library is loaded.
+ *
+ * This is limited, as:
+ * - Arguments are not supported
+ * - Thread time is not reported
+ * - Two events with the same name cannot be in progress at the same time.
+ *
+ * Events recorded here are buffered in Java until the native library is available. Then it waits
+ * for the completion of pending events, and sends the events to the native side.
+ *
+ * Locking: This class is threadsafe. It is enabled when general tracing is, and then disabled when
+ * tracing is enabled from the native side. Event completions are still processed as long
+ * as some are pending, then early tracing is permanently disabled after dumping the
+ * events. This means that if any early event is still pending when tracing is disabled,
+ * all early events are dropped.
+ */
+@JNINamespace("base::android")
+public class EarlyTraceEvent {
+ // Must be kept in sync with the native kAndroidTraceConfigFile.
+ private static final String TRACE_CONFIG_FILENAME = "/data/local/chrome-trace-config.json";
+
+ /** Single trace event. */
+ @VisibleForTesting
+ static final class Event {
+ final String mName;
+ final int mThreadId;
+ final long mBeginTimeMs;
+ long mEndTimeMs;
+
+ Event(String name) {
+ mName = name;
+ mThreadId = Process.myTid();
+ mBeginTimeMs = SystemClock.elapsedRealtime();
+ }
+
+ void end() {
+ assert mEndTimeMs == 0;
+ mEndTimeMs = SystemClock.elapsedRealtime();
+ }
+ }
+
+ // State transitions are:
+ // - enable(): DISABLED -> ENABLED
+ // - disable(): ENABLED -> FINISHING
+ // - Once there are no pending events: FINISHING -> FINISHED.
+ @VisibleForTesting static final int STATE_DISABLED = 0;
+ @VisibleForTesting static final int STATE_ENABLED = 1;
+ @VisibleForTesting static final int STATE_FINISHING = 2;
+ @VisibleForTesting static final int STATE_FINISHED = 3;
+
+ // Locks the fields below.
+ private static final Object sLock = new Object();
+
+ @VisibleForTesting static volatile int sState = STATE_DISABLED;
+ // Not final as these object are not likely to be used at all.
+ @VisibleForTesting static List<Event> sCompletedEvents;
+ @VisibleForTesting static Map<String, Event> sPendingEvents;
+
+ /** @see TraceEvent#MaybeEnableEarlyTracing().
+ */
+ @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
+ static void maybeEnable() {
+ boolean shouldEnable = false;
+ // Checking for the trace config filename touches the disk.
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ CommandLine commandLine = CommandLine.getInstance();
+ if (commandLine != null && commandLine.hasSwitch("trace-startup")) {
+ shouldEnable = true;
+ } else {
+ try {
+ shouldEnable = (new File(TRACE_CONFIG_FILENAME)).exists();
+ } catch (SecurityException e) {
+ // Access denied, not enabled.
+ }
+ }
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ if (shouldEnable) enable();
+ }
+
+ @VisibleForTesting
+ static void enable() {
+ synchronized (sLock) {
+ if (sState != STATE_DISABLED) return;
+ sCompletedEvents = new ArrayList<Event>();
+ sPendingEvents = new HashMap<String, Event>();
+ sState = STATE_ENABLED;
+ }
+ }
+
+ /**
+ * Disables Early tracing.
+ *
+ * Once this is called, no new event will be registered. However, end() calls are still recorded
+ * as long as there are pending events. Once there are none left, pass the events to the native
+ * side.
+ */
+ static void disable() {
+ synchronized (sLock) {
+ if (sState != STATE_ENABLED) return;
+ sState = STATE_FINISHING;
+ maybeFinishLocked();
+ }
+ }
+
+ /** @see {@link TraceEvent#begin()}. */
+ public static void begin(String name) {
+ // begin() and end() are going to be called once per TraceEvent, this avoids entering a
+ // synchronized block at each and every call.
+ if (sState != STATE_ENABLED) return;
+ Event event = new Event(name);
+ Event conflictingEvent;
+ synchronized (sLock) {
+ if (sState != STATE_ENABLED) return;
+ conflictingEvent = sPendingEvents.put(name, event);
+ }
+ if (conflictingEvent != null) {
+ throw new IllegalArgumentException(
+ "Multiple pending trace events can't have the same name");
+ }
+ }
+
+ /** @see {@link TraceEvent#end()}. */
+ public static void end(String name) {
+ int state = sState;
+ if (state != STATE_ENABLED && state != STATE_FINISHING) return;
+ synchronized (sLock) {
+ if (sState != STATE_ENABLED && sState != STATE_FINISHING) return;
+ Event event = sPendingEvents.remove(name);
+ if (event == null) return;
+ event.end();
+ sCompletedEvents.add(event);
+ if (sState == STATE_FINISHING) maybeFinishLocked();
+ }
+ }
+
+ private static void maybeFinishLocked() {
+ if (!sPendingEvents.isEmpty()) return;
+ sState = STATE_FINISHED;
+ dumpEvents(sCompletedEvents);
+ sCompletedEvents = null;
+ sPendingEvents = null;
+ }
+
+ private static void dumpEvents(List<Event> events) {
+ long nativeNowUs = nativeGetTimeTicksNowUs();
+ long javaNowUs = SystemClock.elapsedRealtime() * 1000;
+ long offsetMs = (nativeNowUs - javaNowUs) / 1000;
+ for (Event event : events) {
+ nativeRecordEarlyEvent(event.mName, event.mBeginTimeMs + offsetMs,
+ event.mEndTimeMs + offsetMs, event.mThreadId);
+ }
+ }
+
+ private static native long nativeGetTimeTicksNowUs();
+ private static native void nativeRecordEarlyEvent(
+ String name, long beginTimeMs, long endTimeMs, int threadId);
+}
« 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