Reland of Android: Add support for TraceEvent before the native library is loaded. (patchset #1 id:1 of https://codereview.chromium.org/2145443002/ )

Reason for revert:
Reland.

Original issue's description:
> Revert of Android: Add support for TraceEvent before the native library is loaded. (patchset #12 id:220001 of https://codereview.chromium.org/1486053003/ )
>
> Reason for revert:
> https://crbug.com/627142
>
> Original issue's description:
> > Android: Add support for TraceEvent before the native library is loaded.
> >
> > Currently TraceEvents recorded before the native library load are
> > silently discarded. This CL adds support for such "early" events.
> >
> > The events are buffered in Java, and then sent to the native side once
> > it is available. This support is intentionally simple now. The aim is to
> > ease performance investigation of early startup, and to ease tracking of
> > early startup performance regression, since timings are then accessible
> > to TBM tests.
> >
> > Also use the newly-introduced events in a couple places, and fix a bug
> > in the TraceEvent we use to record the launcher activity lifetime (when
> > an Activity calls finish from onCreate(), onPause() is not called).
> >
> > BUG=564041
> >
> > Committed: https://crrev.com/fb0784294541c53f12e283124672750ab2e291f1
> > Cr-Commit-Position: refs/heads/master@{#404635}
>
> TBR=pasko@chromium.org,yfriedman@chromium.org,jam@chromium.org,lizeb@chromium.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=564041
>
> Committed: https://crrev.com/ffda73103b9a84e4739088175b9250a0c28e6f8c
> Cr-Commit-Position: refs/heads/master@{#404752}

BUG=564041
TBR=jam

Review-Url: https://codereview.chromium.org/2142803002
Cr-Commit-Position: refs/heads/master@{#405120}
diff --git a/base/BUILD.gn b/base/BUILD.gn
index b06028b..b30ca3c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -161,6 +161,8 @@
     "android/context_utils.h",
     "android/cpu_features.cc",
     "android/cxa_demangle_stub.cc",
+    "android/early_trace_event_binding.cc",
+    "android/early_trace_event_binding.h",
     "android/event_log.cc",
     "android/event_log.h",
     "android/field_trial_list.cc",
@@ -2178,6 +2180,7 @@
       "android/java/src/org/chromium/base/ContentUriUtils.java",
       "android/java/src/org/chromium/base/ContextUtils.java",
       "android/java/src/org/chromium/base/CpuFeatures.java",
+      "android/java/src/org/chromium/base/EarlyTraceEvent.java",
       "android/java/src/org/chromium/base/EventLog.java",
       "android/java/src/org/chromium/base/FieldTrialList.java",
       "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
@@ -2239,6 +2242,7 @@
       "android/java/src/org/chromium/base/ContentUriUtils.java",
       "android/java/src/org/chromium/base/ContextUtils.java",
       "android/java/src/org/chromium/base/CpuFeatures.java",
+      "android/java/src/org/chromium/base/EarlyTraceEvent.java",
       "android/java/src/org/chromium/base/EventLog.java",
       "android/java/src/org/chromium/base/FieldTrialList.java",
       "android/java/src/org/chromium/base/FileUtils.java",
diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc
index bc34979c..0142647 100644
--- a/base/android/base_jni_registrar.cc
+++ b/base/android/base_jni_registrar.cc
@@ -13,6 +13,7 @@
 #include "base/android/content_uri_utils.h"
 #include "base/android/context_utils.h"
 #include "base/android/cpu_features.h"
+#include "base/android/early_trace_event_binding.h"
 #include "base/android/event_log.h"
 #include "base/android/field_trial_list.h"
 #include "base/android/important_file_writer_android.h"
@@ -50,6 +51,7 @@
     {"ContentUriUtils", base::RegisterContentUriUtils},
     {"ContextUtils", base::android::RegisterContextUtils},
     {"CpuFeatures", base::android::RegisterCpuFeatures},
+    {"EarlyTraceEvent", base::android::RegisterEarlyTraceEvent},
     {"EventLog", base::android::RegisterEventLog},
     {"FieldTrialList", base::android::RegisterFieldTrialList},
     {"ImportantFileWriterAndroid",
diff --git a/base/android/early_trace_event_binding.cc b/base/android/early_trace_event_binding.cc
new file mode 100644
index 0000000..19e5d8d
--- /dev/null
+++ b/base/android/early_trace_event_binding.cc
@@ -0,0 +1,46 @@
+// 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.
+
+#include "base/android/early_trace_event_binding.h"
+
+#include <stdint.h>
+
+#include "base/android/jni_string.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "jni/EarlyTraceEvent_jni.h"
+
+namespace base {
+namespace android {
+
+const char kEarlyJavaCategory[] = "EarlyJava";
+
+static jlong GetTimeTicksNowUs(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
+  return TimeTicks::Now().ToInternalValue();
+}
+
+static void RecordEarlyEvent(JNIEnv* env,
+                             const JavaParamRef<jclass>& clazz,
+                             const JavaParamRef<jstring>& jname,
+                             jlong begin_time_ms,
+                             jlong end_time_ms,
+                             jint thread_id) {
+  std::string name = ConvertJavaStringToUTF8(env, jname);
+  int64_t begin_us = begin_time_ms * 1000;
+  int64_t end_us = end_time_ms * 1000;
+
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(
+      TRACE_EVENT_PHASE_BEGIN, kEarlyJavaCategory, name.c_str(),
+      trace_event_internal::kNoId, thread_id, begin_us, TRACE_EVENT_FLAG_COPY);
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(
+      TRACE_EVENT_PHASE_END, kEarlyJavaCategory, name.c_str(),
+      trace_event_internal::kNoId, thread_id, end_us, TRACE_EVENT_FLAG_COPY);
+}
+
+bool RegisterEarlyTraceEvent(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/early_trace_event_binding.h b/base/android/early_trace_event_binding.h
new file mode 100644
index 0000000..796544c9
--- /dev/null
+++ b/base/android/early_trace_event_binding.h
@@ -0,0 +1,18 @@
+// 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.
+
+#ifndef BASE_ANDROID_EARLY_TRACE_EVENT_BINDING_H_
+#define BASE_ANDROID_EARLY_TRACE_EVENT_BINDING_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterEarlyTraceEvent(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_EARLY_TRACE_EVENT_BINDING_H_
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 0000000..383a5e2
--- /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 {
+            if (CommandLine.isInitialized()
+                    && CommandLine.getInstance().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);
+}
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java
index 878275c2..95d01dc 100644
--- a/base/android/java/src/org/chromium/base/TraceEvent.java
+++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -16,8 +16,8 @@
  * Java mirror of Chrome trace event API. See base/trace_event/trace_event.h. Unlike the native
  * version, Java does not have stack objects, so a TRACE_EVENT() which does both TRACE_EVENT_BEGIN()
  * and TRACE_EVENT_END() in ctor/dtor is not possible.
- * It is OK to use tracing before the native library has loaded, but such traces will
- * be ignored. (Perhaps we could devise to buffer them up in future?).
+ * It is OK to use tracing before the native library has loaded, in a slightly restricted fashion.
+ * @see EarlyTraceEvent for details.
  */
 @JNINamespace("base::android")
 public class TraceEvent {
@@ -179,6 +179,7 @@
      */
     @CalledByNative
     public static void setEnabled(boolean enabled) {
+        if (enabled) EarlyTraceEvent.disable();
         sEnabled = enabled;
         // Android M+ systrace logs this on its own. Only log it if not writing to Android systrace.
         if (sATraceEnabled) return;
@@ -187,6 +188,15 @@
     }
 
     /**
+     * May enable early tracing depending on the environment.
+     *
+     * Must be called after the command-line has been read.
+     */
+    public static void maybeEnableEarlyTracing() {
+        EarlyTraceEvent.maybeEnable();
+    }
+
+    /**
      * Enables or disabled Android systrace path of Chrome tracing. If enabled, all Chrome
      * traces will be also output to Android systrace. Because of the overhead of Android
      * systrace, this is for WebView only.
@@ -254,7 +264,7 @@
      * @param name The name of the event.
      */
     public static void begin(String name) {
-        if (sEnabled) nativeBegin(name, null);
+        begin(name, null);
     }
 
     /**
@@ -263,6 +273,7 @@
      * @param arg  The arguments of the event.
      */
     public static void begin(String name, String arg) {
+        EarlyTraceEvent.begin(name);
         if (sEnabled) nativeBegin(name, arg);
     }
 
@@ -271,7 +282,7 @@
      * @param name The name of the event.
      */
     public static void end(String name) {
-        if (sEnabled) nativeEnd(name, null);
+        end(name, null);
     }
 
     /**
@@ -280,6 +291,7 @@
      * @param arg  The arguments of the event.
      */
     public static void end(String name, String arg) {
+        EarlyTraceEvent.end(name);
         if (sEnabled) nativeEnd(name, arg);
     }
 
diff --git a/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java b/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java
new file mode 100644
index 0000000..c2efb9e
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java
@@ -0,0 +1,152 @@
+// 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.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.test.util.Feature;
+
+/**
+ * Tests for {@link EarlyTraceEvent}.
+ */
+public class EarlyTraceEventTest extends InstrumentationTestCase {
+    private static final String EVENT_NAME = "MyEvent";
+    private static final String EVENT_NAME2 = "MyOtherEvent";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER)
+                .ensureInitialized(getInstrumentation().getTargetContext());
+
+        EarlyTraceEvent.sState = EarlyTraceEvent.STATE_DISABLED;
+        EarlyTraceEvent.sCompletedEvents = null;
+        EarlyTraceEvent.sPendingEvents = null;
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testCanRecordEvent() {
+        EarlyTraceEvent.enable();
+        long myThreadId = Process.myTid();
+        long beforeMs = SystemClock.elapsedRealtime();
+        EarlyTraceEvent.begin(EVENT_NAME);
+        EarlyTraceEvent.end(EVENT_NAME);
+        long afterMs = SystemClock.elapsedRealtime();
+
+        assertEquals(1, EarlyTraceEvent.sCompletedEvents.size());
+        assertTrue(EarlyTraceEvent.sPendingEvents.isEmpty());
+        EarlyTraceEvent.Event event = EarlyTraceEvent.sCompletedEvents.get(0);
+        assertEquals(EVENT_NAME, event.mName);
+        assertEquals(myThreadId, event.mThreadId);
+        assertTrue(beforeMs <= event.mBeginTimeMs && event.mBeginTimeMs <= afterMs);
+        assertTrue(event.mBeginTimeMs <= event.mEndTimeMs);
+        assertTrue(beforeMs <= event.mEndTimeMs && event.mEndTimeMs <= afterMs);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testIncompleteEvent() {
+        EarlyTraceEvent.enable();
+        EarlyTraceEvent.begin(EVENT_NAME);
+
+        assertTrue(EarlyTraceEvent.sCompletedEvents.isEmpty());
+        assertEquals(1, EarlyTraceEvent.sPendingEvents.size());
+        EarlyTraceEvent.Event event = EarlyTraceEvent.sPendingEvents.get(EVENT_NAME);
+        assertEquals(EVENT_NAME, event.mName);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testNoDuplicatePendingEvents() {
+        EarlyTraceEvent.enable();
+        EarlyTraceEvent.begin(EVENT_NAME);
+        try {
+            EarlyTraceEvent.begin(EVENT_NAME);
+        } catch (IllegalArgumentException e) {
+            // Expected.
+            return;
+        }
+        fail();
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testIgnoreEventsWhenDisabled() {
+        EarlyTraceEvent.begin(EVENT_NAME);
+        EarlyTraceEvent.end(EVENT_NAME);
+        assertNull(EarlyTraceEvent.sCompletedEvents);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testIgnoreNewEventsWhenFinishing() {
+        EarlyTraceEvent.enable();
+        EarlyTraceEvent.begin(EVENT_NAME);
+        EarlyTraceEvent.disable();
+
+        assertEquals(EarlyTraceEvent.STATE_FINISHING, EarlyTraceEvent.sState);
+        EarlyTraceEvent.begin(EVENT_NAME2);
+        EarlyTraceEvent.end(EVENT_NAME2);
+
+        assertEquals(1, EarlyTraceEvent.sPendingEvents.size());
+        assertTrue(EarlyTraceEvent.sCompletedEvents.isEmpty());
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testFinishingToFinished() {
+        EarlyTraceEvent.enable();
+        EarlyTraceEvent.begin(EVENT_NAME);
+        EarlyTraceEvent.disable();
+
+        assertEquals(EarlyTraceEvent.STATE_FINISHING, EarlyTraceEvent.sState);
+        EarlyTraceEvent.begin(EVENT_NAME2);
+        EarlyTraceEvent.end(EVENT_NAME2);
+        EarlyTraceEvent.end(EVENT_NAME);
+
+        assertEquals(EarlyTraceEvent.STATE_FINISHED, EarlyTraceEvent.sState);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testCannotBeReenabledOnceFinished() {
+        EarlyTraceEvent.enable();
+        EarlyTraceEvent.begin(EVENT_NAME);
+        EarlyTraceEvent.end(EVENT_NAME);
+        EarlyTraceEvent.disable();
+        assertEquals(EarlyTraceEvent.STATE_FINISHED, EarlyTraceEvent.sState);
+
+        EarlyTraceEvent.enable();
+        assertEquals(EarlyTraceEvent.STATE_FINISHED, EarlyTraceEvent.sState);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testThreadIdIsRecorded() throws Exception {
+        EarlyTraceEvent.enable();
+        final long[] threadId = {0};
+
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                TraceEvent.begin(EVENT_NAME);
+                threadId[0] = Process.myTid();
+                TraceEvent.end(EVENT_NAME);
+            }
+        };
+        thread.start();
+        thread.join();
+
+        assertEquals(1, EarlyTraceEvent.sCompletedEvents.size());
+        EarlyTraceEvent.Event event = EarlyTraceEvent.sCompletedEvents.get(0);
+        assertEquals(threadId[0], event.mThreadId);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index ffe3e02..1715d7e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -206,6 +206,10 @@
     @Override
     public void onCreate() {
         UmaUtils.recordMainEntryPointTime();
+        initCommandLine();
+        TraceEvent.maybeEnableEarlyTracing();
+        TraceEvent.begin("ChromeApplication.onCreate");
+
         super.onCreate();
         ContextUtils.initApplicationContext(this);
 
@@ -244,6 +248,7 @@
         // in the SyncController constructor.
         UniqueIdentificationGeneratorFactory.registerGenerator(SyncController.GENERATOR_ID,
                 new UuidBasedUniqueIdentificationGenerator(this, SESSIONS_UUID_PREF_KEY), false);
+        TraceEvent.end("ChromeApplication.onCreate");
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index 411b08e..5c9a665 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -116,16 +116,22 @@
     public void onCreate(Bundle savedInstanceState) {
         // Third-party code adds disk access to Activity.onCreate. http://crbug.com/619824
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        TraceEvent.begin("ChromeLauncherActivity");
+        TraceEvent.begin("ChromeLauncherActivity.onCreate");
         try {
-            super.onCreate(savedInstanceState);
+            doOnCreate(savedInstanceState);
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
+            TraceEvent.end("ChromeLauncherActivity.onCreate");
         }
+    }
+
+    private final void doOnCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
         // This Activity is only transient. It launches another activity and
         // terminates itself. However, some of the work is performed outside of
         // {@link Activity#onCreate()}. To capture this, the TraceEvent starts
         // in onCreate(), and ends in onPause().
-        TraceEvent.begin("ChromeLauncherActivity");
         // Needs to be called as early as possible, to accurately capture the
         // time at which the intent was received.
         IntentHandler.addTimestampToIntent(getIntent());
@@ -231,8 +237,8 @@
     }
 
     @Override
-    public void onPause() {
-        super.onPause();
+    public void onDestroy() {
+        super.onDestroy();
         TraceEvent.end("ChromeLauncherActivity");
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index 30b6da5..729f2d2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -201,6 +201,12 @@
      */
     @Override
     protected final void onCreate(Bundle savedInstanceState) {
+        TraceEvent.begin("AsyncInitializationActivity.onCreate()");
+        onCreateInternal(savedInstanceState);
+        TraceEvent.end("AsyncInitializationActivity.onCreate()");
+    }
+
+    private final void onCreateInternal(Bundle savedInstanceState) {
         if (DocumentModeAssassin.getInstance().isMigrationNecessary()) {
             super.onCreate(null);