Commit 5b3bf8df authored by Sky Malice's avatar Sky Malice Committed by Commit Bot

Revert "Redesign ATrace integration"

This reverts commit 80207c25.

Reason for revert: Flaking tests, see crbug.com/1117683

Original change's description:
> Redesign ATrace integration
>
> Chrome and WebView have supported basic Android ATrace tracing, but the
> current approach has some shortcomings:
>
> 1) Android R changes the way atrace session activations are broadcast,
>    breaking the code in WebView listening for activations
>    (OnTraceEnabledChangeListener). This means you can't trace a running
>    WebView app with atrace.
>
> 2) Neither Chrome nor WebView record early startup events to atrace,
>    which means all events before the native library has loaded are
>    lost.
>
> 3) It's not possible to specify trace categories via atrace, which means
>    we need more cumbersome alternative solutions (i.e., command line
>    flags) for startup tracing.
>
> 4) Writing ATrace events is only supported in WebView.
>
> This patch reworks the ATrace integration to resolve these problems and
> to align the Chrome and WebView implementations. In short, ATrace
> session management is moved to the common (TraceEvent) layer, and Chrome
> and WebView only differ by which trace tags they listen to (APP vs.
> WEBVIEW).
>
> We also add a way to declare trace categories through per-app tags:
>
> $ atrace -a org.chromium.chrome,org.chromium.chrome/<category_filter>
>
> (Note that the plain package name without any category filters must
> always appear in the list on its own.)
>
> Multiple categories can be separated with a double colon:
>
> $ atrace -a org.chromium.chrome,org.chromium.chrome/cat1:cat2
>
> Or by specifying the the app several times to get around the 91
> character limit for each entry:
>
> $ atrace -a org.chromium.chrome,\
>             org.chromium.chrome/cat1,\
>             org.chromium.chrome/cat2
>
> Finally, to capture Java startup events into a tracing session
> controlled by the system's Perfetto service instead of atrace, a
> special "-atrace" category can be used to only write events into
> Chrome's own tracing service instead of atrace. This way when we
> connect to Perfetto later in the startup sequence and establish
> the real tracing session, startup-related events can be flushed
> into that session without emitting duplicate events into ATrace.
>
> # Basic trace while Chrome is running. Generates ATrace with Chrome
> # events.
> TEST=atrace -a org.chromium.chrome
>
> # Ditto for WebView.
> TEST=atrace webview
>
> # Startup trace -- open Chrome after running this. Results in an ATrace
> # with Chrome pre- and post-startup events.
> TEST=atrace -a org.chromium.chrome
>
> # Ditto for WebView.
> TEST=atrace webview
>
> # Trace with custom categories. Results in a ATrace with only
> # "cc" events from Chrome.
> TEST=atrace -a org.chromium.chrome,org.chromium.chrome/-*:cc
>
> # Ditto for WebView, using GMail as a test app.
> TEST=atrace -a com.google.android.gm,com.google.android.gm/-*:cc webview
>
> # Chrome-only trace. No Chrome events written in the resulting ATrace.
> TEST=atrace -a org.chromium.chrome,org.chromium.chrome/-atrace
>
> Bug: 1095587, b/160768681
> Change-Id: Ia0bee252ce398804c00be8a4179241b75479bf5e
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2332664
> Reviewed-by: Bo <boliu@chromium.org>
> Reviewed-by: Andrew Grieve <agrieve@chromium.org>
> Reviewed-by: Eric Seckler <eseckler@chromium.org>
> Commit-Queue: Bo <boliu@chromium.org>
> Auto-Submit: Sami Kyöstilä <skyostil@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#798791}

TBR=boliu@chromium.org,skyostil@chromium.org,agrieve@chromium.org,eseckler@chromium.org,nuskos@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: 1095587, 1117683
Bug: b/160768681
Change-Id: Iffcaebb70c6eb92da1cb3080e8034ea5c36e5394
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2363564
Commit-Queue: Sky Malice <skym@chromium.org>
Reviewed-by: default avatarSky Malice <skym@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799456}
parent 7881e219
...@@ -16,6 +16,8 @@ import android.webkit.GeolocationPermissions; ...@@ -16,6 +16,8 @@ import android.webkit.GeolocationPermissions;
import android.webkit.WebStorage; import android.webkit.WebStorage;
import android.webkit.WebViewDatabase; import android.webkit.WebViewDatabase;
import com.android.webview.chromium.WebViewDelegateFactory.WebViewDelegate;
import org.chromium.android_webview.AwBrowserContext; import org.chromium.android_webview.AwBrowserContext;
import org.chromium.android_webview.AwBrowserProcess; import org.chromium.android_webview.AwBrowserProcess;
import org.chromium.android_webview.AwContents; import org.chromium.android_webview.AwContents;
...@@ -95,8 +97,6 @@ public class WebViewChromiumAwInit { ...@@ -95,8 +97,6 @@ public class WebViewChromiumAwInit {
mFactory = factory; mFactory = factory;
// Do not make calls into 'factory' in this ctor - this ctor is called from the // Do not make calls into 'factory' in this ctor - this ctor is called from the
// WebViewChromiumFactoryProvider ctor, so 'factory' is not properly initialized yet. // WebViewChromiumFactoryProvider ctor, so 'factory' is not properly initialized yet.
TraceEvent.maybeEnableEarlyTracing(
TraceEvent.ATRACE_TAG_WEBVIEW, /*readCommandLine=*/false);
} }
public AwTracingController getAwTracingController() { public AwTracingController getAwTracingController() {
...@@ -126,6 +126,7 @@ public class WebViewChromiumAwInit { ...@@ -126,6 +126,7 @@ public class WebViewChromiumAwInit {
protected void startChromiumLocked() { protected void startChromiumLocked() {
try (ScopedSysTraceEvent event = try (ScopedSysTraceEvent event =
ScopedSysTraceEvent.scoped("WebViewChromiumAwInit.startChromiumLocked")) { ScopedSysTraceEvent.scoped("WebViewChromiumAwInit.startChromiumLocked")) {
TraceEvent.setATraceEnabled(mFactory.getWebViewDelegate().isTraceTagEnabled());
assert Thread.holdsLock(mLock) && ThreadUtils.runningOnUiThread(); assert Thread.holdsLock(mLock) && ThreadUtils.runningOnUiThread();
// The post-condition of this method is everything is ready, so notify now to cover all // The post-condition of this method is everything is ready, so notify now to cover all
...@@ -177,6 +178,14 @@ public class WebViewChromiumAwInit { ...@@ -177,6 +178,14 @@ public class WebViewChromiumAwInit {
mSharedStatics.setWebContentsDebuggingEnabledUnconditionally(true); mSharedStatics.setWebContentsDebuggingEnabledUnconditionally(true);
} }
mFactory.getWebViewDelegate().setOnTraceEnabledChangeListener(
new WebViewDelegate.OnTraceEnabledChangeListener() {
@Override
public void onTraceEnabledChange(boolean enabled) {
TraceEvent.setATraceEnabled(enabled);
}
});
mStarted = true; mStarted = true;
RecordHistogram.recordSparseHistogram("Android.WebView.TargetSdkVersion", RecordHistogram.recordSparseHistogram("Android.WebView.TargetSdkVersion",
......
...@@ -11,6 +11,7 @@ import android.content.pm.PackageInfo; ...@@ -11,6 +11,7 @@ import android.content.pm.PackageInfo;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.os.Trace;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.View; import android.view.View;
...@@ -40,6 +41,17 @@ class WebViewDelegateFactory { ...@@ -40,6 +41,17 @@ class WebViewDelegateFactory {
* See {@link WebViewDelegateFactory} for the reasons why this copy is needed. * See {@link WebViewDelegateFactory} for the reasons why this copy is needed.
*/ */
interface WebViewDelegate extends AwDrawFnImpl.DrawFnAccess { interface WebViewDelegate extends AwDrawFnImpl.DrawFnAccess {
/** @see android.webkit.WebViewDelegate.OnTraceEnabledChangeListener */
interface OnTraceEnabledChangeListener {
void onTraceEnabledChange(boolean enabled);
}
/** @see android.webkit.WebViewDelegate#setOnTraceEnabledChangeListener */
void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener);
/** @see android.webkit.WebViewDelegate#isTraceTagEnabled */
boolean isTraceTagEnabled();
/** @see android.webkit.WebViewDelegate#canInvokeDrawGlFunctor */ /** @see android.webkit.WebViewDelegate#canInvokeDrawGlFunctor */
boolean canInvokeDrawGlFunctor(View containerView); boolean canInvokeDrawGlFunctor(View containerView);
...@@ -111,6 +123,22 @@ class WebViewDelegateFactory { ...@@ -111,6 +123,22 @@ class WebViewDelegateFactory {
mDelegate = delegate; mDelegate = delegate;
} }
@Override
public void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener) {
mDelegate.setOnTraceEnabledChangeListener(
new android.webkit.WebViewDelegate.OnTraceEnabledChangeListener() {
@Override
public void onTraceEnabledChange(boolean enabled) {
listener.onTraceEnabledChange(enabled);
}
});
}
@Override
public boolean isTraceTagEnabled() {
return mDelegate.isTraceTagEnabled();
}
@Override @Override
public boolean canInvokeDrawGlFunctor(View containerView) { public boolean canInvokeDrawGlFunctor(View containerView) {
return mDelegate.canInvokeDrawGlFunctor(containerView); return mDelegate.canInvokeDrawGlFunctor(containerView);
...@@ -206,7 +234,12 @@ class WebViewDelegateFactory { ...@@ -206,7 +234,12 @@ class WebViewDelegateFactory {
* framework. * framework.
*/ */
private static class Api21CompatibilityDelegate implements WebViewDelegate { private static class Api21CompatibilityDelegate implements WebViewDelegate {
/** Copy of Trace.TRACE_TAG_WEBVIEW */
private static final long TRACE_TAG_WEBVIEW = 1L << 4;
/** Hidden APIs released in the API 21 version of the framework */ /** Hidden APIs released in the API 21 version of the framework */
private final Method mIsTagEnabledMethod;
private final Method mAddChangeCallbackMethod;
private final Method mGetViewRootImplMethod; private final Method mGetViewRootImplMethod;
private final Method mInvokeFunctorMethod; private final Method mInvokeFunctorMethod;
private final Method mCallDrawGLFunctionMethod; private final Method mCallDrawGLFunctionMethod;
...@@ -222,6 +255,9 @@ class WebViewDelegateFactory { ...@@ -222,6 +255,9 @@ class WebViewDelegateFactory {
// Important: This reflection essentially defines a snapshot of some hidden APIs // Important: This reflection essentially defines a snapshot of some hidden APIs
// at version 21 of the framework for compatibility reasons, and the reflection // at version 21 of the framework for compatibility reasons, and the reflection
// should not be changed even if those hidden APIs change in future releases. // should not be changed even if those hidden APIs change in future releases.
mIsTagEnabledMethod = Trace.class.getMethod("isTagEnabled", long.class);
mAddChangeCallbackMethod = Class.forName("android.os.SystemProperties")
.getMethod("addChangeCallback", Runnable.class);
mGetViewRootImplMethod = View.class.getMethod("getViewRootImpl"); mGetViewRootImplMethod = View.class.getMethod("getViewRootImpl");
mInvokeFunctorMethod = mInvokeFunctorMethod =
Class.forName("android.view.ViewRootImpl") Class.forName("android.view.ViewRootImpl")
...@@ -244,6 +280,29 @@ class WebViewDelegateFactory { ...@@ -244,6 +280,29 @@ class WebViewDelegateFactory {
} }
} }
@Override
public void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener) {
try {
mAddChangeCallbackMethod.invoke(null, new Runnable() {
@Override
public void run() {
listener.onTraceEnabledChange(isTraceTagEnabled());
}
});
} catch (Exception e) {
throw new RuntimeException("Invalid reflection", e);
}
}
@Override
public boolean isTraceTagEnabled() {
try {
return ((Boolean) mIsTagEnabledMethod.invoke(null, TRACE_TAG_WEBVIEW));
} catch (Exception e) {
throw new RuntimeException("Invalid reflection", e);
}
}
@Override @Override
public boolean canInvokeDrawGlFunctor(View containerView) { public boolean canInvokeDrawGlFunctor(View containerView) {
try { try {
......
...@@ -71,12 +71,10 @@ public class AwShellActivity extends Activity { ...@@ -71,12 +71,10 @@ public class AwShellActivity extends Activity {
AwBrowserProcess.loadLibrary(null); AwBrowserProcess.loadLibrary(null);
// This flag is deprecated. Print a hint instead.
if (CommandLine.getInstance().hasSwitch(AwShellSwitches.ENABLE_ATRACE)) { if (CommandLine.getInstance().hasSwitch(AwShellSwitches.ENABLE_ATRACE)) {
Log.e(TAG, "To trace the test shell, run \"atrace webview\""); Log.e(TAG, "Enabling Android trace.");
TraceEvent.setATraceEnabled(true);
} }
TraceEvent.maybeEnableEarlyTracing(
TraceEvent.ATRACE_TAG_WEBVIEW, /*readCommandLine=*/false);
setContentView(R.layout.testshell_activity); setContentView(R.layout.testshell_activity);
......
...@@ -9,7 +9,7 @@ package org.chromium.android_webview.shell; ...@@ -9,7 +9,7 @@ package org.chromium.android_webview.shell;
* the android_webview glue layer. * the android_webview glue layer.
*/ */
public abstract class AwShellSwitches { public abstract class AwShellSwitches {
// Deprecated: instead, run "atrace webview". // Enables Android systrace path for Chrome traces.
public static final String ENABLE_ATRACE = "enable-atrace"; public static final String ENABLE_ATRACE = "enable-atrace";
// Prevent instantiation. // Prevent instantiation.
......
...@@ -148,6 +148,7 @@ public class EarlyTraceEvent { ...@@ -148,6 +148,7 @@ public class EarlyTraceEvent {
if (shouldEnable) enable(); if (shouldEnable) enable();
} }
@VisibleForTesting
static void enable() { static void enable() {
synchronized (sLock) { synchronized (sLock) {
if (sState != STATE_DISABLED) return; if (sState != STATE_DISABLED) return;
......
...@@ -10,16 +10,10 @@ import android.os.SystemClock; ...@@ -10,16 +10,10 @@ import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import android.util.Printer; import android.util.Printer;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex; import org.chromium.base.annotations.MainDex;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import java.lang.reflect.Method;
/** /**
* Java mirror of Chrome trace event API. See base/trace_event/trace_event.h. * Java mirror of Chrome trace event API. See base/trace_event/trace_event.h.
* *
...@@ -39,318 +33,8 @@ import java.lang.reflect.Method; ...@@ -39,318 +33,8 @@ import java.lang.reflect.Method;
@JNINamespace("base::android") @JNINamespace("base::android")
@MainDex @MainDex
public class TraceEvent implements AutoCloseable { public class TraceEvent implements AutoCloseable {
private static volatile boolean sEnabled; // True when tracing into Chrome's tracing service. private static volatile boolean sEnabled;
private static volatile boolean sATraceEnabled; // True when taking an Android systrace.
// Trace tags replicated from android.os.Trace.
public static final long ATRACE_TAG_WEBVIEW = 1L << 4;
public static final long ATRACE_TAG_APP = 1L << 12;
/**
* Watches for active ATrace sessions and accordingly enables or disables
* tracing in Chrome/WebView.
*/
private static class ATrace implements MessageQueue.IdleHandler {
private static final String TAG = "ATrace";
private Class<?> mTraceClass;
private Method mIsTraceTagEnabledMethod;
private Method mTraceBeginMethod;
private Method mTraceEndMethod;
private Method mAsyncTraceBeginMethod;
private Method mAsyncTraceEndMethod;
private Class<?> mSystemPropertiesClass;
private Method mGetSystemPropertyMethod;
private boolean mNativeTracingReady;
private long mTraceTag;
private boolean mTraceTagActive;
private boolean mShouldWriteToSystemTrace;
private static class CategoryConfig {
public String filter = "";
public boolean shouldWriteToATrace = true;
}
public ATrace(long traceTag) {
// Look up hidden ATrace APIs.
try {
mTraceClass = Class.forName("android.os.Trace");
mIsTraceTagEnabledMethod = mTraceClass.getMethod("isTagEnabled", long.class);
mTraceBeginMethod = mTraceClass.getMethod("traceBegin", long.class, String.class);
mTraceEndMethod = mTraceClass.getMethod("traceEnd", long.class);
mAsyncTraceBeginMethod = mTraceClass.getMethod(
"asyncTraceBegin", long.class, String.class, int.class);
mAsyncTraceEndMethod =
mTraceClass.getMethod("asyncTraceEnd", long.class, String.class, int.class);
mSystemPropertiesClass = Class.forName("android.os.SystemProperties");
mGetSystemPropertyMethod = mSystemPropertiesClass.getMethod("get", String.class);
} catch (Exception e) {
// If we hit reflection errors, just disable atrace support.
org.chromium.base.Log.w(TAG, "Reflection error", e);
mIsTraceTagEnabledMethod = null;
}
// If there's an active atrace session, also start collecting early trace events.
mTraceTag = traceTag;
pollConfig();
}
/**
* Reads a system property and returns its string value.
*
* @param name the name of the system property
* @return the result string or null if an exception occurred
*/
@Nullable
private String getSystemProperty(String name) {
try {
return (String) mGetSystemPropertyMethod.invoke(mSystemPropertiesClass, name);
} catch (Exception e) {
return null;
}
}
/**
* Reads a system property and returns its value as an integer.
*
* @param name the name of the system property
* @return the result integer or null if an exception occurred
*/
private Integer getIntegerSystemProperty(String name) {
String property = getSystemProperty(name);
if (property == null) return null;
try {
return Integer.decode(property);
} catch (NumberFormatException e) {
return null;
}
}
private boolean isTraceTagEnabled(long traceTag) {
try {
return (boolean) mIsTraceTagEnabledMethod.invoke(mTraceClass, traceTag);
} catch (Exception e) {
return false;
}
}
/**
* @return true if Chrome/WebView is part of an active ATrace session.
*/
public boolean hasActiveSession() {
return mTraceTagActive;
}
/**
* Checks whether ATrace has started or stopped tracing since the last
* call to this function and parses the changed config if necessary.
*
* @return true if a session has started or stopped.
*/
@UiThread
private boolean pollConfig() {
// ATrace's tracing configuration consists of the following system
// properties:
// - debug.atrace.tags.enableflags: A hex mask of the enabled system
// tracing categories (e.g, "0x10").
// - debug.atrace.app_number: The number of per-app config entries
// (e.g., "1").
// - debug.atrace.app_0: Config for app 0 (up to
// app_number-1).
//
// Normally the per-app config entry is just the package name, but we
// also support setting the trace config with additional parameters,
// e.g., assuming "com.android.chrome" as the package name:
//
// - Enable default categories: "com.android.chrome"
// - Enable specific categories: "com.android.chrome/cat1:cat2"
// - Disable specific categories: "com.android.chrome/*:-cat1"
//
// Since each app-specific config is limited to 91 characters, multiple
// entries can be used to work around the limit.
//
// If either the "webview" trace tag (0x10) is enabled (for WebView)
// or our package name is found in the list of configs, trace events
// will be written into ATrace. However, if "-atrace" appears as a
// category in any of the app-specific configs, events will only be
// written into Chrome's own startup tracing buffer to avoid
// duplicate events.
boolean traceTagActive = isTraceTagEnabled(mTraceTag);
if (mTraceTagActive == traceTagActive) return false;
mTraceTagActive = traceTagActive;
if (!mTraceTagActive) {
// A previously active atrace session ended.
EarlyTraceEvent.disable();
disableNativeATrace();
mShouldWriteToSystemTrace = false;
ThreadUtils.getUiThreadLooper().setMessageLogging(null);
return true;
}
CategoryConfig config = getCategoryConfigFromATrace();
// There is an active atrace session. We can output events into one
// of the following sinks:
//
// - To ATrace:
// ...via TraceLog if native has finished loading.
// ...via android.os.Trace otherwise.
// - To Chrome's own tracing service (for startup tracing):
// ...via TraceLog if native has finished loading.
// ...via EarlyTraceEvent otherwise.
mShouldWriteToSystemTrace = false;
if (mNativeTracingReady) {
// Native is loaded; start writing to atrace via TraceLog, or in
// the case of a Chrome-only trace, setup a startup tracing
// session.
if (config.shouldWriteToATrace) {
enableNativeATrace(config.filter);
} else {
setupATraceStartupTrace(config.filter);
}
} else {
// Native isn't there yet; fall back to android.os.Trace or
// EarlyTraceEvent. We can't use the category filter in this
// case because Java events don't have categories.
if (config.shouldWriteToATrace) {
mShouldWriteToSystemTrace = true;
} else {
EarlyTraceEvent.enable();
}
}
// For Chrome-only traces, also capture Looper messages. In other
// cases, they are logged by the system.
if (!config.shouldWriteToATrace) {
ThreadUtils.getUiThreadLooper().setMessageLogging(LooperMonitorHolder.sInstance);
}
return true;
}
private CategoryConfig getCategoryConfigFromATrace() {
CategoryConfig config = new CategoryConfig();
boolean shouldWriteToATrace = true;
Integer appCount = getIntegerSystemProperty("debug.atrace.app_number");
// In the case of WebView, the application context may not have been
// attached yet. Ignore per-app category settings in that case; they
// will be applied when the native library finishes loading.
if (appCount != null && appCount > 0 && ContextUtils.getApplicationContext() != null) {
// Look for tracing category settings meant for this activity.
// For Chrome this is the package name of the browser, while for
// WebView this is the package name of the hosting application
// (e.g., GMail).
String packageName = ContextUtils.getApplicationContext().getPackageName();
for (int i = 0; i < appCount; i++) {
String appConfig = getSystemProperty("debug.atrace.app_" + i);
if (appConfig == null || !appConfig.startsWith(packageName)) continue;
String extra = appConfig.substring(packageName.length());
if (!extra.startsWith("/")) continue;
for (String category : extra.substring(1).split(":")) {
if (category.equals("-atrace")) {
config.shouldWriteToATrace = false;
continue;
}
if (config.filter.length() > 0) config.filter += ",";
config.filter += category;
}
}
}
return config;
}
public void onNativeTracingReady() {
if (!ThreadUtils.runningOnUiThread()) {
ThreadUtils.postOnUiThread(() -> { onNativeTracingReady(); });
return;
}
mNativeTracingReady = true;
// Since Android R there's no way for an app to be notified of
// atrace activations. To work around this, we poll for the latest
// state whenever the main run loop becomes idle. Since the check
// amounts to one JNI call, the overhead of doing this is
// negligible. See queueIdle().
Looper.myQueue().addIdleHandler(this);
// If there already was an active atrace session, we should transfer
// it over to native.
mTraceTagActive = false;
pollConfig();
}
@Override
public final boolean queueIdle() {
pollConfig();
return true;
}
/**
* Instructs Chrome's tracing service to start tracing.
*
* @param categoryFilter Set of trace categories to enable.
*/
private void enableNativeATrace(String categoryFilter) {
assert mNativeTracingReady;
TraceEventJni.get().startATrace(categoryFilter);
}
/**
* Stop a previously started tracing session and flush remaining events
* to ATrace (if enabled).
*/
private void disableNativeATrace() {
assert mNativeTracingReady;
TraceEventJni.get().stopATrace();
}
/**
* Begins a startup tracing session which will be later taken over by a
* system tracing session.
*
* @param categoryFilter Set of trace categories to enable.
*/
private void setupATraceStartupTrace(String categoryFilter) {
assert mNativeTracingReady;
TraceEventJni.get().setupATraceStartupTrace(categoryFilter);
}
public void traceBegin(String name) {
if (!mShouldWriteToSystemTrace) return;
try {
mTraceBeginMethod.invoke(mTraceClass, mTraceTag, name);
} catch (Exception e) {
// No-op.
}
}
public void traceEnd() {
if (!mShouldWriteToSystemTrace) return;
try {
mTraceEndMethod.invoke(mTraceClass, mTraceTag);
} catch (Exception e) {
// No-op.
}
}
public void asyncTraceBegin(String name, int cookie) {
if (!mShouldWriteToSystemTrace) return;
try {
mAsyncTraceBeginMethod.invoke(mTraceClass, mTraceTag, name, cookie);
} catch (Exception e) {
// No-op.
}
}
public void asyncTraceEnd(String name, int cookie) {
if (!mShouldWriteToSystemTrace) return;
try {
mAsyncTraceEndMethod.invoke(mTraceClass, mTraceTag, name, cookie);
} catch (Exception e) {
// No-op.
}
}
}
private static ATrace sATrace;
private static class BasicLooperMonitor implements Printer { private static class BasicLooperMonitor implements Printer {
private static final String LOOPER_TASK_PREFIX = "Looper.dispatch: "; private static final String LOOPER_TASK_PREFIX = "Looper.dispatch: ";
...@@ -372,8 +56,6 @@ public class TraceEvent implements AutoCloseable { ...@@ -372,8 +56,6 @@ public class TraceEvent implements AutoCloseable {
// will filter the event in this case. // will filter the event in this case.
boolean earlyTracingActive = EarlyTraceEvent.enabled(); boolean earlyTracingActive = EarlyTraceEvent.enabled();
if (sEnabled || earlyTracingActive) { if (sEnabled || earlyTracingActive) {
// Note that we don't need to log ATrace events here because the
// framework does that for us (M+).
mCurrentTarget = getTraceEventName(line); mCurrentTarget = getTraceEventName(line);
if (sEnabled) { if (sEnabled) {
TraceEventJni.get().beginToplevel(mCurrentTarget); TraceEventJni.get().beginToplevel(mCurrentTarget);
...@@ -585,6 +267,13 @@ public class TraceEvent implements AutoCloseable { ...@@ -585,6 +267,13 @@ public class TraceEvent implements AutoCloseable {
return scoped(name, null); return scoped(name, null);
} }
/**
* Register an enabled observer, such that java traces are always enabled with native.
*/
public static void registerNativeEnabledObserver() {
TraceEventJni.get().registerEnabledObserver();
}
/** /**
* Notification from native that tracing is enabled/disabled. * Notification from native that tracing is enabled/disabled.
*/ */
...@@ -597,41 +286,40 @@ public class TraceEvent implements AutoCloseable { ...@@ -597,41 +286,40 @@ public class TraceEvent implements AutoCloseable {
sEnabled = enabled; sEnabled = enabled;
// Android M+ systrace logs this on its own. Only log it if not writing to Android // Android M+ systrace logs this on its own. Only log it if not writing to Android
// systrace. // systrace.
if (sATrace != null && !sATrace.hasActiveSession()) { if (sATraceEnabled) return;
ThreadUtils.getUiThreadLooper().setMessageLogging( ThreadUtils.getUiThreadLooper().setMessageLogging(
enabled ? LooperMonitorHolder.sInstance : null); enabled ? LooperMonitorHolder.sInstance : null);
}
} }
} }
/** /**
* May enable early tracing depending on the environment. * May enable early tracing depending on the environment.
* *
* @param traceTag If non-zero, start watching for ATrace sessions on the given tag. * Must be called after the command-line has been read.
* @param readCommandLine If true, also check command line flags to see
* whether tracing should be turned on.
*/ */
public static void maybeEnableEarlyTracing(long traceTag, boolean readCommandLine) { public static void maybeEnableEarlyTracing() {
// Enable early trace events based on command line flags. This is only EarlyTraceEvent.maybeEnable();
// done for Chrome since WebView tracing isn't controlled with command if (EarlyTraceEvent.enabled()) {
// line flags.
if (readCommandLine) {
EarlyTraceEvent.maybeEnable();
}
if (traceTag != 0) {
sATrace = new ATrace(traceTag);
}
if (EarlyTraceEvent.enabled() && (sATrace == null || !sATrace.hasActiveSession())) {
ThreadUtils.getUiThreadLooper().setMessageLogging(LooperMonitorHolder.sInstance); ThreadUtils.getUiThreadLooper().setMessageLogging(LooperMonitorHolder.sInstance);
} }
} }
public static void onNativeTracingReady() { /**
// Register an enabled observer, such that java traces are always * Enables or disabled Android systrace path of Chrome tracing. If enabled, all Chrome
// enabled with native. * traces will be also output to Android systrace. Because of the overhead of Android
TraceEventJni.get().registerEnabledObserver(); * systrace, this is for WebView only.
if (sATrace != null) { */
sATrace.onNativeTracingReady(); public static void setATraceEnabled(boolean enabled) {
if (sATraceEnabled == enabled) return;
sATraceEnabled = enabled;
if (enabled) {
// Calls TraceEvent.setEnabled(true) via
// TraceLog::EnabledStateObserver::OnTraceLogEnabled
TraceEventJni.get().startATrace();
} else {
// Calls TraceEvent.setEnabled(false) via
// TraceLog::EnabledStateObserver::OnTraceLogDisabled
TraceEventJni.get().stopATrace();
} }
} }
...@@ -668,11 +356,7 @@ public class TraceEvent implements AutoCloseable { ...@@ -668,11 +356,7 @@ public class TraceEvent implements AutoCloseable {
*/ */
public static void startAsync(String name, long id) { public static void startAsync(String name, long id) {
EarlyTraceEvent.startAsync(name, id); EarlyTraceEvent.startAsync(name, id);
if (sEnabled) { if (sEnabled) TraceEventJni.get().startAsync(name, id);
TraceEventJni.get().startAsync(name, id);
} else if (sATrace != null) {
sATrace.asyncTraceBegin(name, (int) id);
}
} }
/** /**
...@@ -682,11 +366,7 @@ public class TraceEvent implements AutoCloseable { ...@@ -682,11 +366,7 @@ public class TraceEvent implements AutoCloseable {
*/ */
public static void finishAsync(String name, long id) { public static void finishAsync(String name, long id) {
EarlyTraceEvent.finishAsync(name, id); EarlyTraceEvent.finishAsync(name, id);
if (sEnabled) { if (sEnabled) TraceEventJni.get().finishAsync(name, id);
TraceEventJni.get().finishAsync(name, id);
} else if (sATrace != null) {
sATrace.asyncTraceEnd(name, (int) id);
}
} }
/** /**
...@@ -704,11 +384,7 @@ public class TraceEvent implements AutoCloseable { ...@@ -704,11 +384,7 @@ public class TraceEvent implements AutoCloseable {
*/ */
public static void begin(String name, String arg) { public static void begin(String name, String arg) {
EarlyTraceEvent.begin(name, false /*isToplevel*/); EarlyTraceEvent.begin(name, false /*isToplevel*/);
if (sEnabled) { if (sEnabled) TraceEventJni.get().begin(name, arg);
TraceEventJni.get().begin(name, arg);
} else if (sATrace != null) {
sATrace.traceBegin(name);
}
} }
/** /**
...@@ -726,19 +402,14 @@ public class TraceEvent implements AutoCloseable { ...@@ -726,19 +402,14 @@ public class TraceEvent implements AutoCloseable {
*/ */
public static void end(String name, String arg) { public static void end(String name, String arg) {
EarlyTraceEvent.end(name, false /*isToplevel*/); EarlyTraceEvent.end(name, false /*isToplevel*/);
if (sEnabled) { if (sEnabled) TraceEventJni.get().end(name, arg);
TraceEventJni.get().end(name, arg);
} else if (sATrace != null) {
sATrace.traceEnd();
}
} }
@NativeMethods @NativeMethods
interface Natives { interface Natives {
void registerEnabledObserver(); void registerEnabledObserver();
void startATrace(String categoryFilter); void startATrace();
void stopATrace(); void stopATrace();
void setupATraceStartupTrace(String categoryFilter);
void instant(String name, String arg); void instant(String name, String arg);
void begin(String name, String arg); void begin(String name, String arg);
void end(String name, String arg); void end(String name, String arg);
......
...@@ -633,7 +633,7 @@ public class LibraryLoader { ...@@ -633,7 +633,7 @@ public class LibraryLoader {
UmaRecorderHolder.onLibraryLoaded(); UmaRecorderHolder.onLibraryLoaded();
// From now on, keep tracing in sync with native. // From now on, keep tracing in sync with native.
TraceEvent.onNativeTracingReady(); TraceEvent.registerNativeEnabledObserver();
// From this point on, native code is ready to use, but non-MainDex JNI may not yet have // From this point on, native code is ready to use, but non-MainDex JNI may not yet have
// been registered. Check isInitialized() to be sure that initialization is fully complete. // been registered. Check isInitialized() to be sure that initialization is fully complete.
......
...@@ -49,39 +49,22 @@ static void JNI_TraceEvent_RegisterEnabledObserver(JNIEnv* env) { ...@@ -49,39 +49,22 @@ static void JNI_TraceEvent_RegisterEnabledObserver(JNIEnv* env) {
std::make_unique<TraceEnabledObserver>()); std::make_unique<TraceEnabledObserver>());
} }
static void JNI_TraceEvent_StartATrace( static void JNI_TraceEvent_StartATrace(JNIEnv* env) {
JNIEnv* env, base::trace_event::TraceLog::GetInstance()->StartATrace();
const JavaParamRef<jstring>& category_filter) {
std::string category_filter_utf8 =
ConvertJavaStringToUTF8(env, category_filter);
base::trace_event::TraceLog::GetInstance()->StartATrace(category_filter_utf8);
} }
static void JNI_TraceEvent_StopATrace(JNIEnv* env) { static void JNI_TraceEvent_StopATrace(JNIEnv* env) {
base::trace_event::TraceLog::GetInstance()->StopATrace(); base::trace_event::TraceLog::GetInstance()->StopATrace();
} }
static void JNI_TraceEvent_SetupATraceStartupTrace(
JNIEnv* env,
const JavaParamRef<jstring>& category_filter) {
std::string category_filter_utf8 =
ConvertJavaStringToUTF8(env, category_filter);
base::trace_event::TraceLog::GetInstance()->SetupATraceStartupTrace(
category_filter_utf8);
}
#else // BUILDFLAG(ENABLE_BASE_TRACING) #else // BUILDFLAG(ENABLE_BASE_TRACING)
// Empty implementations when TraceLog isn't available. // Empty implementations when TraceLog isn't available.
static void JNI_TraceEvent_RegisterEnabledObserver(JNIEnv* env) { static void JNI_TraceEvent_RegisterEnabledObserver(JNIEnv* env) {
base::android::Java_TraceEvent_setEnabled(env, false); base::android::Java_TraceEvent_setEnabled(env, false);
} }
static void JNI_TraceEvent_StartATrace(JNIEnv* env, static void JNI_TraceEvent_StartATrace(JNIEnv* env) {}
base::android::JavaParamRef<jstring>&) {}
static void JNI_TraceEvent_StopATrace(JNIEnv* env) {} static void JNI_TraceEvent_StopATrace(JNIEnv* env) {}
static void JNI_TraceEvent_SetupATraceStartupTrace(
JNIEnv* env,
base::android::JavaParamRef<jstring>&) {}
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
......
...@@ -34,10 +34,7 @@ void WriteToATrace(int fd, const char* buffer, size_t size) { ...@@ -34,10 +34,7 @@ void WriteToATrace(int fd, const char* buffer, size_t size) {
break; break;
total_written += written; total_written += written;
} }
// Tracing might have been disabled before we were notified about it, which if (total_written < size) {
// triggers EBADF. Since enabling and disabling atrace is racy, ignore the
// error in that case to avoid logging an error for every trace event.
if (total_written < size && errno != EBADF) {
PLOG(WARNING) << "Failed to write buffer '" << std::string(buffer, size) PLOG(WARNING) << "Failed to write buffer '" << std::string(buffer, size)
<< "' to " << kATraceMarkerFile; << "' to " << kATraceMarkerFile;
} }
...@@ -76,6 +73,20 @@ void WriteEvent(char phase, ...@@ -76,6 +73,20 @@ void WriteEvent(char phase,
WriteToATrace(g_atrace_fd, out.c_str(), out.size()); WriteToATrace(g_atrace_fd, out.c_str(), out.size());
} }
void NoOpOutputCallback(WaitableEvent* complete_event,
const scoped_refptr<RefCountedString>&,
bool has_more_events) {
if (!has_more_events)
complete_event->Signal();
}
void EndChromeTracing(TraceLog* trace_log,
WaitableEvent* complete_event) {
trace_log->SetDisabled();
// Delete the buffered trace events as they have been sent to atrace.
trace_log->Flush(BindRepeating(&NoOpOutputCallback, complete_event));
}
} // namespace } // namespace
// These functions support Android systrace.py when 'webview' category is // These functions support Android systrace.py when 'webview' category is
...@@ -88,7 +99,7 @@ void WriteEvent(char phase, ...@@ -88,7 +99,7 @@ void WriteEvent(char phase,
// StartATrace, StopATrace and SendToATrace, and perhaps send Java traces // StartATrace, StopATrace and SendToATrace, and perhaps send Java traces
// directly to atrace in trace_event_binding.cc. // directly to atrace in trace_event_binding.cc.
void TraceLog::StartATrace(const std::string& category_filter) { void TraceLog::StartATrace() {
if (g_atrace_fd != -1) if (g_atrace_fd != -1)
return; return;
...@@ -97,17 +108,28 @@ void TraceLog::StartATrace(const std::string& category_filter) { ...@@ -97,17 +108,28 @@ void TraceLog::StartATrace(const std::string& category_filter) {
PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile; PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
return; return;
} }
TraceConfig trace_config(category_filter); TraceConfig trace_config;
trace_config.SetTraceRecordMode(RECORD_CONTINUOUSLY); trace_config.SetTraceRecordMode(RECORD_CONTINUOUSLY);
SetEnabled(trace_config, TraceLog::RECORDING_MODE); SetEnabled(trace_config, TraceLog::RECORDING_MODE);
} }
void TraceLog::StopATrace() { void TraceLog::StopATrace() {
if (g_atrace_fd != -1) { if (g_atrace_fd == -1)
close(g_atrace_fd); return;
g_atrace_fd = -1;
} close(g_atrace_fd);
SetDisabled(); g_atrace_fd = -1;
// TraceLog::Flush() requires the current thread to have a message loop, but
// this thread called from Java may not have one, so flush in another thread.
Thread end_chrome_tracing_thread("end_chrome_tracing");
WaitableEvent complete_event(WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED);
end_chrome_tracing_thread.Start();
end_chrome_tracing_thread.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&EndChromeTracing, Unretained(this),
Unretained(&complete_event)));
complete_event.Wait();
} }
void TraceEvent::SendToATrace() { void TraceEvent::SendToATrace() {
...@@ -176,13 +198,5 @@ void TraceLog::AddClockSyncMetadataEvent() { ...@@ -176,13 +198,5 @@ void TraceLog::AddClockSyncMetadataEvent() {
close(atrace_fd); close(atrace_fd);
} }
void TraceLog::SetupATraceStartupTrace(const std::string& category_filter) {
atrace_startup_config_ = TraceConfig(category_filter);
}
Optional<TraceConfig> TraceLog::TakeATraceStartupConfig() {
return std::move(atrace_startup_config_);
}
} // namespace trace_event } // namespace trace_event
} // namespace base } // namespace base
...@@ -12,20 +12,11 @@ namespace trace_event { ...@@ -12,20 +12,11 @@ namespace trace_event {
TEST(TraceEventAndroidTest, WriteToATrace) { TEST(TraceEventAndroidTest, WriteToATrace) {
// Just a smoke test to ensure no crash. // Just a smoke test to ensure no crash.
TraceLog* trace_log = TraceLog::GetInstance(); TraceLog* trace_log = TraceLog::GetInstance();
trace_log->StartATrace("test"); trace_log->StartATrace();
TRACE_EVENT0("test", "test-event"); TRACE_EVENT0("test", "test-event");
trace_log->StopATrace(); trace_log->StopATrace();
trace_log->AddClockSyncMetadataEvent(); trace_log->AddClockSyncMetadataEvent();
} }
TEST(TraceEventAndroidTest, ATraceStartup) {
TraceLog* trace_log = TraceLog::GetInstance();
EXPECT_FALSE(trace_log->TakeATraceStartupConfig());
trace_log->SetupATraceStartupTrace("cat");
auto config = trace_log->TakeATraceStartupConfig();
EXPECT_TRUE(config);
EXPECT_TRUE(config->IsCategoryGroupEnabled("cat"));
}
} // namespace trace_event } // namespace trace_event
} // namespace base } // namespace base
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/time/time_override.h" #include "base/time/time_override.h"
#include "base/trace_event/category_registry.h" #include "base/trace_event/category_registry.h"
...@@ -107,12 +106,10 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider { ...@@ -107,12 +106,10 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
int GetNumTracesRecorded(); int GetNumTracesRecorded();
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
void StartATrace(const std::string& category_filter); void StartATrace();
void StopATrace(); void StopATrace();
void AddClockSyncMetadataEvent(); void AddClockSyncMetadataEvent();
void SetupATraceStartupTrace(const std::string& category_filter); #endif
Optional<TraceConfig> TakeATraceStartupConfig();
#endif // defined(OS_ANDROID)
// Enabled state listeners give a callback when tracing is enabled or // Enabled state listeners give a callback when tracing is enabled or
// disabled. This can be used to tie into other library's tracing systems // disabled. This can be used to tie into other library's tracing systems
...@@ -579,10 +576,6 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider { ...@@ -579,10 +576,6 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
FilterFactoryForTesting filter_factory_for_testing_; FilterFactoryForTesting filter_factory_for_testing_;
#if defined(OS_ANDROID)
base::Optional<TraceConfig> atrace_startup_config_;
#endif
DISALLOW_COPY_AND_ASSIGN(TraceLog); DISALLOW_COPY_AND_ASSIGN(TraceLog);
}; };
......
...@@ -7,7 +7,6 @@ package org.chromium.chrome.browser; ...@@ -7,7 +7,6 @@ package org.chromium.chrome.browser;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
...@@ -93,14 +92,8 @@ public class ChromeApplication extends Application { ...@@ -93,14 +92,8 @@ public class ChromeApplication extends Application {
CommandLineInitUtil.initCommandLine( CommandLineInitUtil.initCommandLine(
COMMAND_LINE_FILE, ChromeApplication::shouldUseDebugFlags); COMMAND_LINE_FILE, ChromeApplication::shouldUseDebugFlags);
// Enable ATrace on debug OS or app builds.
int applicationFlags = context.getApplicationInfo().flags;
boolean isAppDebuggable = (applicationFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
boolean isOsDebuggable = BuildInfo.isDebugAndroid();
// Requires command-line flags. // Requires command-line flags.
TraceEvent.maybeEnableEarlyTracing( TraceEvent.maybeEnableEarlyTracing();
(isAppDebuggable || isOsDebuggable) ? TraceEvent.ATRACE_TAG_APP : 0,
/*readCommandLine=*/true);
TraceEvent.begin("ChromeApplication.attachBaseContext"); TraceEvent.begin("ChromeApplication.attachBaseContext");
// Register for activity lifecycle callbacks. Must be done before any activities are // Register for activity lifecycle callbacks. Must be done before any activities are
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_log.h"
#include "base/values.h" #include "base/values.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/tracing/common/tracing_switches.h" #include "components/tracing/common/tracing_switches.h"
...@@ -96,10 +95,6 @@ TraceStartupConfig::TraceStartupConfig() { ...@@ -96,10 +95,6 @@ TraceStartupConfig::TraceStartupConfig() {
DCHECK(!IsTracingStartupForDuration()); DCHECK(!IsTracingStartupForDuration());
DCHECK_EQ(SessionOwner::kBackgroundTracing, session_owner_); DCHECK_EQ(SessionOwner::kBackgroundTracing, session_owner_);
CHECK(!ShouldTraceToResultFile()); CHECK(!ShouldTraceToResultFile());
} else if (EnableFromATrace()) {
DCHECK(IsEnabled());
DCHECK_EQ(SessionOwner::kSystemTracing, session_owner_);
CHECK(!ShouldTraceToResultFile());
} }
} }
...@@ -201,24 +196,6 @@ bool TraceStartupConfig::EnableFromCommandLine() { ...@@ -201,24 +196,6 @@ bool TraceStartupConfig::EnableFromCommandLine() {
return true; return true;
} }
bool TraceStartupConfig::EnableFromATrace() {
#if defined(OS_ANDROID)
auto atrace_config =
base::trace_event::TraceLog::GetInstance()->TakeATraceStartupConfig();
if (!atrace_config)
return false;
trace_config_ = *atrace_config;
is_enabled_ = true;
// We only support ATrace-initiated startup tracing together with the system
// service, because DevTools and background tracing generally use Chrome
// command line flags to control startup tracing instead of ATrace.
session_owner_ = SessionOwner::kSystemTracing;
return true;
#else // defined(OS_ANDROID)
return false;
#endif // !defined(OS_ANDROID)
}
bool TraceStartupConfig::EnableFromConfigFile() { bool TraceStartupConfig::EnableFromConfigFile() {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
base::FilePath trace_config_file(kAndroidTraceConfigFile); base::FilePath trace_config_file(kAndroidTraceConfigFile);
......
...@@ -157,7 +157,6 @@ class TRACING_EXPORT TraceStartupConfig { ...@@ -157,7 +157,6 @@ class TRACING_EXPORT TraceStartupConfig {
bool EnableFromCommandLine(); bool EnableFromCommandLine();
bool EnableFromConfigFile(); bool EnableFromConfigFile();
bool EnableFromBackgroundTracing(); bool EnableFromBackgroundTracing();
bool EnableFromATrace();
bool ParseTraceConfigFileContent(const std::string& content); bool ParseTraceConfigFileContent(const std::string& content);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment