Merge "Add WebView Tracing API."
diff --git a/api/current.txt b/api/current.txt
index e97670a..a01de4f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -49586,6 +49586,44 @@
     method public void proceed();
   }
 
+  public class TracingConfig {
+    ctor public TracingConfig(int);
+    ctor public TracingConfig(int, java.lang.String, int);
+    method public java.lang.String getCustomCategoryPattern();
+    method public int getPresetCategories();
+    method public int getTracingMode();
+    field public static final int CATEGORIES_FRAME_VIEWER = 4; // 0x4
+    field public static final int CATEGORIES_INPUT_LATENCY = 1; // 0x1
+    field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3; // 0x3
+    field public static final int CATEGORIES_NONE = -1; // 0xffffffff
+    field public static final int CATEGORIES_RENDERING = 2; // 0x2
+    field public static final int CATEGORIES_WEB_DEVELOPER = 0; // 0x0
+    field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
+    field public static final int RECORD_TO_CONSOLE = 3; // 0x3
+    field public static final int RECORD_UNTIL_FULL = 0; // 0x0
+    field public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2; // 0x2
+  }
+
+  public abstract class TracingController {
+    ctor public TracingController();
+    method public static android.webkit.TracingController getInstance();
+    method public abstract boolean isTracing();
+    method public abstract boolean start(android.webkit.TracingConfig);
+    method public abstract boolean stop();
+    method public abstract boolean stopAndFlush(android.webkit.TracingController.TracingOutputStream, android.os.Handler);
+  }
+
+  public static abstract interface TracingController.TracingOutputStream {
+    method public abstract void complete();
+    method public abstract void write(byte[]);
+  }
+
+  public class TracingFileOutputStream implements android.webkit.TracingController.TracingOutputStream {
+    ctor public TracingFileOutputStream(java.lang.String) throws java.io.FileNotFoundException;
+    method public void complete();
+    method public void write(byte[]);
+  }
+
   public final class URLUtil {
     ctor public URLUtil();
     method public static java.lang.String composeSearchUrl(java.lang.String, java.lang.String, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index eb0b133..30e4cbc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4637,6 +4637,7 @@
     method public abstract android.webkit.ServiceWorkerController getServiceWorkerController();
     method public abstract android.webkit.WebViewFactoryProvider.Statics getStatics();
     method public abstract android.webkit.TokenBindingService getTokenBindingService();
+    method public abstract android.webkit.TracingController getTracingController();
     method public abstract android.webkit.WebIconDatabase getWebIconDatabase();
     method public abstract android.webkit.WebStorage getWebStorage();
     method public abstract android.webkit.WebViewDatabase getWebViewDatabase(android.content.Context);
diff --git a/core/java/android/webkit/TracingConfig.java b/core/java/android/webkit/TracingConfig.java
new file mode 100644
index 0000000..75e2bf7
--- /dev/null
+++ b/core/java/android/webkit/TracingConfig.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Holds tracing configuration information and predefined settings.
+ */
+public class TracingConfig {
+
+    private final String mCustomCategoryPattern;
+    private final @PresetCategories int mPresetCategories;
+    private @TracingMode int mTracingMode;
+
+    /** @hide */
+    @IntDef({CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER, CATEGORIES_INPUT_LATENCY,
+            CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING, CATEGORIES_FRAME_VIEWER})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PresetCategories {}
+
+    /**
+     * Indicates that there are no preset categories.
+     */
+    public static final int CATEGORIES_NONE = -1;
+
+    /**
+     * Predefined categories typically useful for web developers.
+     * Typically includes blink, compositor, renderer.scheduler and v8 categories.
+     */
+    public static final int CATEGORIES_WEB_DEVELOPER = 0;
+
+    /**
+     * Predefined categories for analyzing input latency issues.
+     * Typically includes input, renderer.scheduler categories.
+     */
+    public static final int CATEGORIES_INPUT_LATENCY = 1;
+
+    /**
+     * Predefined categories for analyzing rendering issues.
+     * Typically includes blink, compositor and gpu categories.
+     */
+    public static final int CATEGORIES_RENDERING = 2;
+
+    /**
+     * Predefined categories for analyzing javascript and rendering issues.
+     * Typically includes blink, compositor, gpu, renderer.schduler and v8 categories.
+     */
+    public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3;
+
+    /**
+     * Predefined categories for studying difficult rendering performance problems.
+     * Typically includes blink, compositor, gpu, renderer.scheduler, v8 and
+     * some other compositor categories which are disabled by default.
+     */
+    public static final int CATEGORIES_FRAME_VIEWER = 4;
+
+    /** @hide */
+    @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER,
+            RECORD_TO_CONSOLE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TracingMode {}
+
+    /**
+     * Record trace events until the internal tracing buffer is full. Default tracing mode.
+     * Typically the buffer memory usage is between {@link #RECORD_CONTINUOUSLY} and the
+     * {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}. Depending on the implementation typically allows
+     * up to 256k events to be stored.
+     */
+    public static final int RECORD_UNTIL_FULL = 0;
+
+    /**
+     * Record trace events continuously using an internal ring buffer. Overwrites
+     * old events if they exceed buffer capacity. Uses less memory than both
+     * {@link #RECORD_UNTIL_FULL} and {@link #RECORD_UNTIL_FULL_LARGE_BUFFER} modes.
+     * Depending on the implementation typically allows up to 64k events to be stored.
+     */
+    public static final int RECORD_CONTINUOUSLY = 1;
+
+    /**
+     * Record trace events using a larger internal tracing buffer until it is full.
+     * Uses more memory than the other modes and may not be suitable on devices
+     * with smaller RAM. Depending on the implementation typically allows up to
+     * 512 million events to be stored.
+     */
+    public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2;
+
+    /**
+     * Record trace events to console (logcat). The events are discarded and nothing
+     * is sent back to the caller. Uses the least memory as compared to the other modes.
+     */
+    public static final int RECORD_TO_CONSOLE = 3;
+
+    /**
+     * Create config with the preset categories.
+     * <p>
+     * Example:
+     *    TracingConfig(CATEGORIES_WEB_DEVELOPER) -- records trace events from the "web developer"
+     *                                               preset categories.
+     *
+     * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
+     *                    {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
+     *                    {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
+     *                    {@link #CATEGORIES_FRAME_VIEWER}.
+     *
+     * Note: for specifying custom categories without presets use
+     * {@link #TracingConfig(int, String, int)}.
+     *
+     */
+    public TracingConfig(@PresetCategories int presetCategories) {
+        this(presetCategories, "", RECORD_UNTIL_FULL);
+    }
+
+    /**
+     * Create a configuration with both preset categories and custom categories.
+     * Also allows to specify the tracing mode.
+     *
+     * Note that the categories are defined by the currently-in-use version of WebView. They live
+     * in chromium code and are not part of the Android API. See
+     * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
+     * chromium documentation on tracing</a> for more details.
+     *
+     * <p>
+     * Examples:
+     *
+     *  Preset category with a specified trace mode:
+     *    TracingConfig(CATEGORIES_WEB_DEVELOPER, "", RECORD_UNTIL_FULL_LARGE_BUFFER);
+     *  Custom categories:
+     *    TracingConfig(CATEGORIES_NONE, "browser", RECORD_UNTIL_FULL)
+     *      -- records only the trace events from the "browser" category.
+     *    TraceConfig(CATEGORIES_NONE, "-input,-gpu", RECORD_UNTIL_FULL)
+     *      -- records all trace events excluding the events from the "input" and 'gpu' categories.
+     *    TracingConfig(CATEGORIES_NONE, "blink*,devtools*", RECORD_UNTIL_FULL)
+     *      -- records only the trace events matching the "blink*" and "devtools*" patterns
+     *         (e.g. "blink_gc" and "devtools.timeline" categories).
+     *
+     *  Combination of preset and additional custom categories:
+     *    TracingConfig(CATEGORIES_WEB_DEVELOPER, "memory-infra", RECORD_CONTINUOUSLY)
+     *      -- records events from the "web developer" categories and events from the "memory-infra"
+     *         category to understand where memory is being used.
+     *
+     * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
+     *                    {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
+     *                    {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
+     *                    {@link #CATEGORIES_FRAME_VIEWER}.
+     * @param customCategories a comma-delimited list of category wildcards. A category can
+     *                         have an optional '-' prefix to make it an excluded category.
+     * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
+     *                    {@link #RECORD_CONTINUOUSLY}, {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}
+     *                    or {@link #RECORD_TO_CONSOLE}.
+     */
+    public TracingConfig(@PresetCategories int presetCategories,
+            @NonNull String customCategories, @TracingMode int tracingMode) {
+        mPresetCategories = presetCategories;
+        mCustomCategoryPattern = customCategories;
+        mTracingMode = RECORD_UNTIL_FULL;
+    }
+
+    /**
+     * Returns the custom category pattern for this configuration.
+     *
+     * @return empty string if no custom category pattern is specified.
+     */
+    @NonNull
+    public String getCustomCategoryPattern() {
+        return mCustomCategoryPattern;
+    }
+
+    /**
+     * Returns the preset categories value of this configuration.
+     */
+    @PresetCategories
+    public int getPresetCategories() {
+        return mPresetCategories;
+    }
+
+    /**
+     * Returns the tracing mode of this configuration.
+     */
+    @TracingMode
+    public int getTracingMode() {
+        return mTracingMode;
+    }
+
+}
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
new file mode 100644
index 0000000..cadb8a1
--- /dev/null
+++ b/core/java/android/webkit/TracingController.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+
+/**
+ * Manages tracing of WebViews. In particular provides functionality for the app
+ * to enable/disable tracing of parts of code and to collect tracing data.
+ * This is useful for profiling performance issues, debugging and memory usage
+ * analysis in production and real life scenarios.
+ * <p>
+ * The resulting trace data is sent back as a byte sequence in json format. This
+ * file can be loaded in "chrome://tracing" for further analysis.
+ * <p>
+ * Note: All methods in this class must be called on the UI thread. All callbacks
+ * are also called on the UI thread.
+ * <p>
+ * Example usage:
+ * <pre class="prettyprint">
+ * TracingController tracingController = TracingController.getInstance();
+ * tracingController.start(new TraceConfig(CATEGORIES_WEB_DEVELOPER));
+ * [..]
+ * tracingController.stopAndFlush(new TraceFileOutput("trace.json"), null);
+ * </pre></p>
+ */
+public abstract class TracingController {
+
+    /**
+     * Interface for capturing tracing data.
+     */
+    public interface TracingOutputStream {
+        /**
+         * Will be called to return tracing data in chunks.
+         * Tracing data is returned in json format an array of bytes.
+         */
+        void write(byte[] chunk);
+
+        /**
+         * Called when tracing is finished and the data collection is over.
+         * There will be no calls to #write after #complete is called.
+         */
+        void complete();
+    }
+
+    /**
+     * Returns the default TracingController instance. At present there is
+     * only one TracingController instance for all WebView instances,
+     * however this restriction may be relaxed in the future.
+     *
+     * @return the default TracingController instance
+     */
+    @NonNull
+    public static TracingController getInstance() {
+        return WebViewFactory.getProvider().getTracingController();
+    }
+
+    /**
+     * Starts tracing all webviews. Depeding on the trace mode in traceConfig
+     * specifies how the trace events are recorded.
+     *
+     * For tracing modes {@link TracingConfig#RECORD_UNTIL_FULL},
+     * {@link TracingConfig#RECORD_CONTINUOUSLY} and
+     * {@link TracingConfig#RECORD_UNTIL_FULL_LARGE_BUFFER} the events are recorded
+     * using an internal buffer and flushed to the outputStream when
+     * {@link #stopAndFlush(TracingOutputStream, Handler)} is called.
+     *
+     * @param tracingConfig configuration options to use for tracing
+     * @return false if the system is already tracing, true otherwise.
+     */
+    public abstract boolean start(TracingConfig tracingConfig);
+
+    /**
+     * Stops tracing and discards all tracing data.
+     *
+     * This method is particularly useful in conjunction with the
+     * {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode because tracing data is logged to
+     * console and not sent to an outputStream as with
+     * {@link #stopAndFlush(TracingOutputStream, Handler)}.
+     *
+     * @return false if the system was not tracing at the time of the call, true
+     *         otherwise.
+     */
+    public abstract boolean stop();
+
+    /**
+     * Stops tracing and flushes tracing data to the specifid outputStream.
+     *
+     * Note that if the {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode is used
+     * nothing will be sent to the outputStream and no TracingOuputStream methods will be
+     * called. In that case it is more convenient to just use {@link #stop()} instead.
+     *
+     * @param outputStream the output steam the tracing data will be sent to.
+     * @param handler the {@link android.os.Handler} on which the outputStream callbacks
+     *                will be invoked. If the handler is null the current thread's Looper
+     *                will be used.
+     * @return false if the system was not tracing at the time of the call, true
+     *         otherwise.
+     */
+    public abstract boolean stopAndFlush(TracingOutputStream outputStream,
+            @Nullable Handler handler);
+
+    /** True if the system is tracing */
+    public abstract boolean isTracing();
+
+    // TODO: consider adding getTraceBufferUsage, percentage and approx event count.
+    // TODO: consider adding String getCategories(), for obtaining the actual list
+    // of categories used (given that presets are ints).
+
+}
diff --git a/core/java/android/webkit/TracingFileOutputStream.java b/core/java/android/webkit/TracingFileOutputStream.java
new file mode 100644
index 0000000..8a5fa36
--- /dev/null
+++ b/core/java/android/webkit/TracingFileOutputStream.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.NonNull;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Simple TracingOutputStream implementation which writes the trace data from
+ * {@link TracingController} to a new file.
+ *
+ */
+public class TracingFileOutputStream implements TracingController.TracingOutputStream {
+
+    private FileOutputStream mFileOutput;
+
+    public TracingFileOutputStream(@NonNull String filename) throws FileNotFoundException {
+        mFileOutput = new FileOutputStream(filename);
+    }
+
+    /**
+     * Writes bytes chunk to the file.
+     */
+    public void write(byte[] chunk) {
+        try {
+            mFileOutput.write(chunk);
+        } catch (IOException e) {
+            onIOException(e);
+        }
+    }
+
+    /**
+     * Closes the file.
+     */
+    public void complete() {
+        try {
+            mFileOutput.close();
+        } catch (IOException e) {
+            onIOException(e);
+        }
+    }
+
+    private void onIOException(IOException e) {
+        throw new RuntimeException(e);
+    }
+}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 4c47abc..3ced6a5 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -134,6 +134,14 @@
     TokenBindingService getTokenBindingService();
 
     /**
+     * Gets the TracingController instance for this WebView implementation. The
+     * implementation must return the same instance on subsequent calls.
+     *
+     * @return the TracingController instance
+     */
+    TracingController getTracingController();
+
+    /**
      * Gets the ServiceWorkerController instance for this WebView implementation. The
      * implementation must return the same instance on subsequent calls.
      *