blob: 1a47c015594db921abe1880405c9d4854c3db1a3 [file] [log] [blame]
// Copyright 2017 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.android_webview;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.chromium.base.TraceRecordMode;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/**
* Manages tracing functionality in WebView.
*/
@JNINamespace("android_webview")
public class AwTracingController {
private static final String TAG = "cr.AwTracingController";
public static final int RESULT_SUCCESS = 0;
public static final int RESULT_ALREADY_TRACING = 1;
public static final int RESULT_INVALID_CATEGORIES = 2;
public static final int RESULT_INVALID_MODE = 3;
public static final int CATEGORIES_ALL = 0;
public static final int CATEGORIES_ANDROID_WEBVIEW = 1;
public static final int CATEGORIES_WEB_DEVELOPER = 2;
public static final int CATEGORIES_INPUT_LATENCY = 3;
public static final int CATEGORIES_RENDERING = 4;
public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 5;
public static final int CATEGORIES_FRAME_VIEWER = 6;
private static final List<String> CATEGORIES_ALL_LIST = new ArrayList<>(Arrays.asList("*"));
private static final List<String> CATEGORIES_ANDROID_WEBVIEW_LIST =
new ArrayList<>(Arrays.asList("android_webview", "Java", "toplevel"));
private static final List<String> CATEGORIES_WEB_DEVELOPER_LIST = new ArrayList<>(
Arrays.asList("blink", "cc", "netlog", "renderer.scheduler", "toplevel", "v8"));
private static final List<String> CATEGORIES_INPUT_LATENCY_LIST = new ArrayList<>(
Arrays.asList("benchmark", "input", "evdev", "renderer.scheduler", "toplevel"));
private static final List<String> CATEGORIES_RENDERING_LIST =
new ArrayList<>(Arrays.asList("blink", "cc", "gpu", "toplevel"));
private static final List<String> CATEGORIES_JAVASCRIPT_AND_RENDERING_LIST = new ArrayList<>(
Arrays.asList("blink", "cc", "gpu", "renderer.scheduler", "v8", "toplevel"));
private static final List<String> CATEGORIES_FRAME_VIEWER_LIST = new ArrayList<>(
Arrays.asList("blink", "cc", "gpu", "renderer.scheduler", "v8", "toplevel",
"disabled-by-default-cc.debug", "disabled-by-default-cc.debug.picture",
"disabled-by-default-cc.debug.display_items"));
private static final List<List<String>> PREDEFINED_CATEGORIES_LIST =
new ArrayList<List<String>>(Arrays.asList(CATEGORIES_ALL_LIST, // CATEGORIES_ALL
CATEGORIES_ANDROID_WEBVIEW_LIST, // CATEGORIES_ANDROID_WEBVIEW
CATEGORIES_WEB_DEVELOPER_LIST, // CATEGORIES_WEB_DEVELOPER
CATEGORIES_INPUT_LATENCY_LIST, // CATEGORIES_INPUT_LATENCY
CATEGORIES_RENDERING_LIST, // CATEGORIES_RENDERING
CATEGORIES_JAVASCRIPT_AND_RENDERING_LIST, // CATEGORIES_JAVASCRIPT_AND_RENDERING
CATEGORIES_FRAME_VIEWER_LIST // CATEGORIES_FRAME_VIEWER
));
private OutputStream mOutputStream;
// TODO(timvolodine): consider caching mIsTracing value for efficiency.
// boolean mIsTracing;
public AwTracingController() {
mNativeAwTracingController = nativeInit();
}
// Start tracing
public int start(Collection<Integer> predefinedCategories,
Collection<String> customIncludedCategories, int mode) {
if (isTracing()) return RESULT_ALREADY_TRACING;
if (!isValid(customIncludedCategories)) return RESULT_INVALID_CATEGORIES;
if (!isValidMode(mode)) return RESULT_INVALID_MODE;
String categoryFilter =
constructCategoryFilterString(predefinedCategories, customIncludedCategories);
nativeStart(mNativeAwTracingController, categoryFilter, mode);
return RESULT_SUCCESS;
}
// Stop tracing and flush tracing data.
public boolean stopAndFlush(@Nullable OutputStream outputStream) {
if (!isTracing()) return false;
mOutputStream = outputStream;
nativeStopAndFlush(mNativeAwTracingController);
return true;
}
public boolean isTracing() {
return nativeIsTracing(mNativeAwTracingController);
}
// Combines configuration bits into a category string usable by chromium.
// Assumes that customIncludedCategories have been validated using isValid() method.
private String constructCategoryFilterString(
Collection<Integer> predefinedCategories, Collection<String> customIncludedCategories) {
// Make sure to remove any doubles in category patterns.
HashSet<String> categoriesSet = new HashSet<String>();
for (int predefinedCategoriesIndex : predefinedCategories) {
categoriesSet.addAll(PREDEFINED_CATEGORIES_LIST.get(predefinedCategoriesIndex));
}
categoriesSet.addAll(customIncludedCategories);
if (categoriesSet.isEmpty()) {
// when no categories are specified -- exclude everything
categoriesSet.add("-*");
}
return TextUtils.join(",", categoriesSet);
}
// Returns true if the given collection of categories is valid.
private static boolean isValid(Collection<String> customIncludedCategories) {
for (String categoryPattern : customIncludedCategories) {
if (!isValidPattern(categoryPattern)) {
return false;
}
}
return true;
}
private static boolean isValidPattern(String pattern) {
// do not allow 'excluded' patterns or comma separated strings
return !pattern.startsWith("-") && !pattern.contains(",");
}
private static boolean isValidMode(int mode) {
// allow only two modes, to ensure limited memory usage.
return (mode == TraceRecordMode.RECORD_UNTIL_FULL
|| mode == TraceRecordMode.RECORD_CONTINUOUSLY);
}
@CalledByNative
private void onTraceDataChunkReceived(byte[] data) throws IOException {
if (mOutputStream != null) {
mOutputStream.write(data);
}
}
@CalledByNative
private void onTraceDataComplete() throws IOException {
if (mOutputStream != null) {
mOutputStream.close();
}
}
private long mNativeAwTracingController;
private native long nativeInit();
private native boolean nativeStart(
long nativeAwTracingController, String categories, int traceMode);
private native boolean nativeStopAndFlush(long nativeAwTracingController);
private native boolean nativeIsTracing(long nativeAwTracingController);
}