Update from https://crrev.com/328418
This includes the switch to libc++ on android.
Fixes outside of the rolled code:
*) ::TestSuite -> base::TestSuite
*) base::ScopedPtrHashMap's second parameter Value->scoped_ptr<Value>
*) re2 std::tr1 changes from upstream libc++ changes
*) tracked_objects:: api changes in mojo/common/task_tracker*
Review URL: https://codereview.chromium.org/1128733002
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 2db7261..e7985ef 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -108,6 +108,8 @@
"android/library_loader/library_load_from_apk_status_codes.h",
"android/library_loader/library_loader_hooks.cc",
"android/library_loader/library_loader_hooks.h",
+ "android/library_loader/library_prefetcher.cc",
+ "android/library_loader/library_prefetcher.h",
"android/locale_utils.cc",
"android/locale_utils.h",
"android/memory_pressure_listener_android.cc",
@@ -174,6 +176,7 @@
"containers/hash_tables.h",
"containers/linked_list.h",
"containers/mru_cache.h",
+ "containers/scoped_ptr_hash_map.h",
"containers/small_map.h",
"containers/stack_container.h",
"cpu.cc",
@@ -280,6 +283,8 @@
"mac/mac_util.mm",
"mac/mach_logging.cc",
"mac/mach_logging.h",
+ "mac/memory_pressure_monitor_mac.cc",
+ "mac/memory_pressure_monitor_mac.h",
"mac/objc_property_releaser.h",
"mac/objc_property_releaser.mm",
"mac/os_crash_dumps.cc",
@@ -1067,6 +1072,7 @@
"android/jni_android_unittest.cc",
"android/jni_array_unittest.cc",
"android/jni_string_unittest.cc",
+ "android/library_loader/library_prefetcher_unittest.cc",
"android/path_utils_unittest.cc",
"android/scoped_java_ref_unittest.cc",
"android/sys_utils_unittest.cc",
@@ -1092,6 +1098,7 @@
"containers/hash_tables_unittest.cc",
"containers/linked_list_unittest.cc",
"containers/mru_cache_unittest.cc",
+ "containers/scoped_ptr_hash_map_unittest.cc",
"containers/small_map_unittest.cc",
"containers/stack_container_unittest.cc",
"cpu_unittest.cc",
@@ -1448,6 +1455,7 @@
android_library("base_java_test_support") {
deps = [
":base_java",
+ "//testing/android/reporter:reporter_java",
]
DEPRECATED_java_in_dir = "test/android/javatests/src"
}
diff --git a/base/android/application_status_listener_unittest.cc b/base/android/application_status_listener_unittest.cc
index 1049628..ce78bf9 100644
--- a/base/android/application_status_listener_unittest.cc
+++ b/base/android/application_status_listener_unittest.cc
@@ -7,7 +7,7 @@
#include "base/callback_forward.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
@@ -49,9 +49,8 @@
void Run() {
// Start the thread and tell it to register for events.
thread_.Start();
- thread_.message_loop()
- ->PostTask(FROM_HERE,
- base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
+ thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
base::Unretained(this)));
// Wait for its completion.
diff --git a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
index d4b0d98..ad5cdd8 100644
--- a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
+++ b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
@@ -9,8 +9,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeAnimator;
import android.animation.TimeAnimator.TimeListener;
-import android.annotation.TargetApi;
-import android.os.Build;
import android.util.Log;
/**
@@ -82,9 +80,6 @@
/**
* Record Android animation frame rate and return the result.
*/
- // Note: TimeAnimator was added to the Android public API in level 16, but has actually been
- // available since level 14. So, it's safe to use TimeAnimator here, even on ICS.
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static class Recorder implements TimeListener {
// TODO(kkimlabs): If we can use in the future, migrate to Choreographer for minimal
// workload.
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 40cb035..3df7b92 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -375,4 +375,16 @@
return res.getDrawable(id);
}
}
+
+ /**
+ * @see android.content.res.Resources#getDrawableForDensity(int id, int density).
+ */
+ @SuppressWarnings("deprecation")
+ public static Drawable getDrawableForDensity(Resources res, int id, int density) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ return res.getDrawableForDensity(id, density, null);
+ } else {
+ return res.getDrawableForDensity(id, density);
+ }
+ }
}
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
index 99d755d..4c79a4d 100644
--- a/base/android/java/src/org/chromium/base/Log.java
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -24,22 +24,23 @@
* calls will be stripped out of the binary. Concatenations and method calls however will still
* remain and be executed. If they can't be avoided, try to generate the logs in a method annotated
* with {@link NoSideEffects}. Another possibility is to use
- * {@link android.util.Log#isLoggable(String, int)}, with {@link Log#makeTag(String)} to get the
- * correct tag.
+ * {@link android.util.Log#isLoggable(String, int)} to guard those calls.
* </p>
*
* Usage:
* <pre>
+ * private static final String TAG = Log.makeTag("Group");
+ *
* private void myMethod(String awesome) {
- * Log.i("Group", "My %s message.", awesome);
- * Log.d("Group", "My debug message");
+ * Log.i(TAG, "My %s message.", awesome);
+ * Log.d(TAG, "My debug message");
* }
* </pre>
*
* Logcat output:
* <pre>
- * I/chromium.Group (999): My awesome message
- * D/chromium.Group (999): [MyClass.java:42] My debug message
+ * I/cr.Group (999): My awesome message
+ * D/cr.Group (999): [MyClass.java:42] My debug message
* </pre>
*
* Set the log level for a given group:
@@ -48,7 +49,25 @@
* </pre>
*/
public class Log {
- private static final String BASE_TAG = "chromium";
+ private static final String BASE_TAG = "cr";
+
+ /** Convenience property, same as {@link android.util.Log#ASSERT}. */
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ /** Convenience property, same as {@link android.util.Log#DEBUG}. */
+ public static final int DEBUG = android.util.Log.DEBUG;
+
+ /** Convenience property, same as {@link android.util.Log#ERROR}. */
+ public static final int ERROR = android.util.Log.ERROR;
+
+ /** Convenience property, same as {@link android.util.Log#INFO}. */
+ public static final int INFO = android.util.Log.INFO;
+
+ /** Convenience property, same as {@link android.util.Log#VERBOSE}. */
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+
+ /** Convenience property, same as {@link android.util.Log#WARN}. */
+ public static final int WARN = android.util.Log.WARN;
private Log() {
// Static only access
@@ -73,13 +92,26 @@
/**
* Returns a full tag for the provided group tag. Full tags longer than 23 characters
- * will cause a runtime exception later. (see {@link android.util.Log#isLoggable(String, int)})
+ * will cause a runtime exception.
*
* @param groupTag {@code null} and empty string are allowed.
+ *
+ * @see android.util.Log#isLoggable(String, int)
+ * @throws IllegalArgumentException if the tag is too long.
*/
public static String makeTag(String groupTag) {
if (TextUtils.isEmpty(groupTag)) return BASE_TAG;
- return BASE_TAG + "." + groupTag;
+ String tag = BASE_TAG + "." + groupTag;
+ if (tag.length() > 23) {
+ throw new IllegalArgumentException(
+ "The full tag (" + tag + ") is longer than 23 characters.");
+ }
+ return tag;
+ }
+
+ /** Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}. */
+ public static boolean isLoggable(String tag, int level) {
+ return android.util.Log.isLoggable(tag, level);
}
/**
@@ -89,16 +121,15 @@
* than 7 parameters, consider building your log message using a function annotated with
* {@link NoSideEffects}.
*
- * @param groupTag Used to identify the source of a log message. It usually refers to the
- * package or feature, to logically group related logs.
+ * @param tag Used to identify the source of a log message. Should be created using
+ * {@link #makeTag(String)}.
*
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
* one is a {@link Throwable}, its trace will be printed.
*/
- private static void verbose(String groupTag, String messageTemplate, Object... args) {
- String tag = makeTag(groupTag);
+ private static void verbose(String tag, String messageTemplate, Object... args) {
if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
String message = formatLogWithStack(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
@@ -111,48 +142,48 @@
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 0 arg version. */
- public static void v(String groupTag, String message) {
- verbose(groupTag, message);
+ public static void v(String tag, String message) {
+ verbose(tag, message);
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
- public static void v(String groupTag, String messageTemplate, Object arg1) {
- verbose(groupTag, messageTemplate, arg1);
+ public static void v(String tag, String messageTemplate, Object arg1) {
+ verbose(tag, messageTemplate, arg1);
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 2 args version */
- public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2) {
- verbose(groupTag, messageTemplate, arg1, arg2);
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2) {
+ verbose(tag, messageTemplate, arg1, arg2);
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 3 args version */
public static void v(
- String groupTag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
- verbose(groupTag, messageTemplate, arg1, arg2, arg3);
+ String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3);
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 4 args version */
- public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4) {
- verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4);
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4);
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 5 args version */
- public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4, Object arg5) {
- verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 6 args version */
- public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4, Object arg5, Object arg6) {
- verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
}
/** Sends a {@link android.util.Log#VERBOSE} log message. 7 args version */
- public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
- verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6, Object arg7) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
/**
@@ -162,16 +193,15 @@
* than 7 parameters, consider building your log message using a function annotated with
* {@link NoSideEffects}.
*
- * @param groupTag Used to identify the source of a log message. It usually refers to the
- * package or feature, to logically group related logs.
+ * @param tag Used to identify the source of a log message. Should be created using
+ * {@link #makeTag(String)}.
*
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
* one is a {@link Throwable}, its trace will be printed.
*/
- private static void debug(String groupTag, String messageTemplate, Object... args) {
- String tag = makeTag(groupTag);
+ private static void debug(String tag, String messageTemplate, Object... args) {
if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
String message = formatLogWithStack(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
@@ -184,60 +214,59 @@
}
/** Sends a {@link android.util.Log#DEBUG} log message. 0 arg version. */
- public static void d(String groupTag, String message) {
- debug(groupTag, message);
+ public static void d(String tag, String message) {
+ debug(tag, message);
}
/** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
- public static void d(String groupTag, String messageTemplate, Object arg1) {
- debug(groupTag, messageTemplate, arg1);
+ public static void d(String tag, String messageTemplate, Object arg1) {
+ debug(tag, messageTemplate, arg1);
}
/** Sends a {@link android.util.Log#DEBUG} log message. 2 args version */
- public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2) {
- debug(groupTag, messageTemplate, arg1, arg2);
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2) {
+ debug(tag, messageTemplate, arg1, arg2);
}
/** Sends a {@link android.util.Log#DEBUG} log message. 3 args version */
public static void d(
- String groupTag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
- debug(groupTag, messageTemplate, arg1, arg2, arg3);
+ String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+ debug(tag, messageTemplate, arg1, arg2, arg3);
}
/** Sends a {@link android.util.Log#DEBUG} log message. 4 args version */
- public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4) {
- debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4);
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4);
}
/** Sends a {@link android.util.Log#DEBUG} log message. 5 args version */
- public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4, Object arg5) {
- debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
}
/** Sends a {@link android.util.Log#DEBUG} log message. 6 args version */
- public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4, Object arg5, Object arg6) {
- debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
}
/** Sends a {@link android.util.Log#DEBUG} log message. 7 args version */
- public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
- Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
- debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6, Object arg7) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
/**
* Sends an {@link android.util.Log#INFO} log message.
*
- * @param groupTag Used to identify the source of a log message. It usually refers to the
- * package or feature, to logically group related logs.
+ * @param tag Used to identify the source of a log message. Should be created using
+ * {@link #makeTag(String)}.
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
* one is a {@link Throwable}, its trace will be printed.
*/
- public static void i(String groupTag, String messageTemplate, Object... args) {
- String tag = makeTag(groupTag);
+ public static void i(String tag, String messageTemplate, Object... args) {
if (android.util.Log.isLoggable(tag, android.util.Log.INFO)) {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
@@ -252,15 +281,14 @@
/**
* Sends a {@link android.util.Log#WARN} log message.
*
- * @param groupTag Used to identify the source of a log message. It usually refers to the
- * package or feature, to logically group related logs.
+ * @param tag Used to identify the source of a log message. Should be created using
+ * {@link #makeTag(String)}.
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
* one is a {@link Throwable}, its trace will be printed.
*/
- public static void w(String groupTag, String messageTemplate, Object... args) {
- String tag = makeTag(groupTag);
+ public static void w(String tag, String messageTemplate, Object... args) {
if (android.util.Log.isLoggable(tag, android.util.Log.WARN)) {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
@@ -275,15 +303,14 @@
/**
* Sends an {@link android.util.Log#ERROR} log message.
*
- * @param groupTag Used to identify the source of a log message. It usually refers to the
- * package or feature, to logically group related logs.
+ * @param tag Used to identify the source of a log message. Should be created using
+ * {@link #makeTag(String)}.
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
* one is a {@link Throwable}, its trace will be printed.
*/
- public static void e(String groupTag, String messageTemplate, Object... args) {
- String tag = makeTag(groupTag);
+ public static void e(String tag, String messageTemplate, Object... args) {
if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
@@ -302,15 +329,14 @@
*
* @see android.util.Log#wtf(String, String, Throwable)
*
- * @param groupTag Used to identify the source of a log message. It usually refers to the
- * package or feature, to logically group related logs.
+ * @param tag Used to identify the source of a log message. Should be created using
+ * {@link #makeTag(String)}.
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
* one is a {@link Throwable}, its trace will be printed.
*/
- public static void wtf(String groupTag, String messageTemplate, Object... args) {
- String tag = makeTag(groupTag);
+ public static void wtf(String tag, String messageTemplate, Object... args) {
if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
diff --git a/base/android/java/src/org/chromium/base/OWNERS b/base/android/java/src/org/chromium/base/OWNERS
new file mode 100644
index 0000000..d99aec1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/OWNERS
@@ -0,0 +1,2 @@
+per-file ApiCompatibilityUtils.java=aurimas@chromium.org
+per-file ApiCompatibilityUtils.java=newt@chromium.org
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index 5da080e..0b3ed20 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -41,7 +41,10 @@
paths[DATA_DIRECTORY] =
appContext.getDir(dataDirectorySuffix[0], Context.MODE_PRIVATE).getPath();
paths[DATABASE_DIRECTORY] = appContext.getDatabasePath("foo").getParent();
- paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
+ // TODO(wnwen): Find a way to avoid calling this function in renderer process.
+ if (appContext.getCacheDir() != null) {
+ paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
+ }
return paths;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, suffix);
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
new file mode 100644
index 0000000..2193826
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/README_logging.md
@@ -0,0 +1,159 @@
+## Logging ##
+
+Logging used to be done using Android's [android.util.Log]
+(http://developer.android.com/reference/android/util/Log.html).
+
+A wrapper on that is now available: org.chromium.base.Log. It is designed to write logs as
+belonging to logical groups going beyond single classes, and to make it easy to switch logging on
+or off for individual groups.
+
+Usage:
+
+ private static final String TAG = Log.makeTag("Tag");
+ ...
+ Log.i(TAG, "Some debug info: %s", data);
+
+Output:
+
+ D/cr.Tag: ( 999): [MyClass.java:42] Some debug info: data's toString output"
+
+Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for example. In most
+cases, the class name is not needed anymore. In Debug and Verbose logs, the file name and line
+number will be prepended to the log message. For higher priority logs, those are currently not
+added for performance concerns. It might be useful to make the log messages meaningful enough so
+that with the group tag, it's easy to pinpoint their origin.
+
+All log calls are guarded, which allows to enable or disable logging specific groups using ADB:
+
+ adb shell setprop log.tag.<YOUR_LOG_TAG> <LEVEL>
+
+Level here is either `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ASSERT`, or `SUPPRESS`, and the
+log tag looks like `cr.Tag`. By default, the level for all tags is `INFO`.
+
+**Caveat:** Property keys are limited to 23 characters. If the tag is too long, `Log#isLoggable`
+throws a RuntimeException.
+
+### Logging Best Practices
+
+#### Rule #1: Never log PII (Personal Identification Information):
+
+This is a huge concern, because other applications can access the log and extract a lot of data
+from your own by doing so. Even if JellyBean restricted this, people are going to run your
+application on rooted devices and allow some apps to access it. Also anyone with USB access to the
+device can use ADB to get the full logcat and get the same data right now.
+
+If you really need to print something , print a series of Xs instead (e.g. "XXXXXX"), or print a
+truncated hash of the PII instead. Truncation is required to make it harder for an attacker to
+recover the full data through rainbow tables and similar methods.
+
+Similarly, avoid dumping API keys, cookies, etc...
+
+#### Rule #2: Do not write debug logs in production code:
+
+The kernel log buffer is global and of limited size. Any extra debug log you add to your activity
+or service makes it more difficult to diagnose problems on other parts of the system, because they
+tend to push the interesting bit out of the buffer too soon. This is a recurring problem on
+Android, so avoid participating into it.
+
+All verbose and debug log calls made using `org.chromium.base.Log` will be stripped out of
+production binaries using Proguard. So there will be no way to get those logs in a release build.
+For other levels, they can be disabled using system properties. Because log messages might not be
+written, the cost of creating them should also be avoided. This can be done using three
+complementary ways:
+
+- Use string formatting instead of concatenations
+
+ // BAD
+ Log.d(TAG, "I " + preference + " writing logs.");
+
+ // BETTER
+ Log.d(TAG, "I %s writing logs.", preference);
+
+ If logging is disabled, the function's arguments will still have to be computed and provided
+ as input. The first call above will always lead to the creation of a `StringBuilder` and a few
+ concatenations, while the second just passes the arguments and won't need that.
+
+- Guard expensive calls
+
+ Sometimes the values to log aren't readily available and need to be computed specially. This
+ should be avoided when logging is disabled.
+
+ Using `Log#isLoggable` will return whether logging for a specific tag is allowed or not. It is
+ the call used inside the log functions and using allows to know when running the expensive
+ functions is needed.
+
+ if (Log.isLoggable(TAG, Log.DEBUG) {
+ Log.d(TAG, "Something happened: %s", dumpDom(tab));
+ }
+
+ For more info, See the [android framework documentation]
+ (http://developer.android.com/tools/debugging/debugging-log.html).
+
+ Using a debug constant is a less flexible, but more perfomance oriented alternative.
+
+ static private final boolean DEBUG = false; // set to 'true' to enable debug
+ ...
+ if (DEBUG) {
+ Log.i(TAG, createThatExpensiveLogMessage(activity))
+ }
+
+ Because the variable is a `static final` that can be evaluated at compile time, the Java
+ compiler will optimize out all guarded calls from the generated `.class` file. Changing it
+ however requires editing each of the files for which debug should be enabled and recompiling,
+ while the previous method can enable or disable debugging for a whole feature without changing
+ any source file.
+
+- Annotate debug functions with the `@NoSideEffects` annotation.
+
+ That annotation tells Proguard to assume that a given function has no side effects, and is
+ called only for its returned value. If this value is unused, the call will be removed. If the
+ function is not called at all, it will also be removed. Since Proguard is already used to
+ strip debug and verbose calls out of release builds, this annotation allows it to have a
+ deeper action by removing also function calls used to generate the log call's arguments.
+
+ /* If that function is only used in Log.d calls, proguard should completely remove it from
+ * the release builds. */
+ @NoSideEffects
+ private static String getSomeDebugLogString(Thing[] things) {
+ /* Still needs to be guarded to avoid impacting debug builds, or in case it's used for
+ * some other log levels. But at least it is done only once, inside the function. */
+ if (!Log.isLoggable(TAG, Log.DEBUG)) return null;
+
+ StringBuilder sb = new StringBuilder("Reporting " + thing.length + " things:");
+ for (Thing thing : things) {
+ sb.append('\n').append(thing.id).append(' ').append(report.foo);
+ }
+ return sb.toString();
+ }
+
+ public void bar() {
+ ...
+ Log.d(TAG, getSomeDebugLogString(things)); /* In debug builds, the function does nothing
+ * is debug is disabled, and the entire line
+ * is removed in release builds. */
+ }
+
+ Again, this is useful only if the input to that function are variables already available in
+ the scope. The idea is to move computations, concatenations, etc. to a place where that can be
+ removed when not needed, without invading the main function's logic.
+
+#### Rule #3: Favor small log messages
+
+This is still related to the global fixed-sized kernel buffer used to keep all logs. Try to make
+your log information as terse as possible. This reduces the risk of pushing interesting log data
+out of the buffer when something really nasty happens. It's really better to have a single-line
+log message, than several ones. I.e. don't use:
+
+ Log.GROUP.d(TAG, "field1 = %s", value1);
+ Log.GROUP.d(TAG, "field2 = %s", value2);
+ Log.GROUP.d(TAG, "field3 = %s", value3);
+
+Instead, write this as:
+
+ Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3);
+
+That doesn't seem to be much different if you count overall character counts, but each independent
+log entry also implies a small, but non-trivial header, in the kernel log buffer.
+And since every byte count, you can also try something even shorter, as in:
+
+ Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3);
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index 2a8deeb..c0b9172 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -176,6 +176,7 @@
* @param task The Runnable to run
* @param delayMillis The delay in milliseconds until the Runnable will be run
*/
+ @VisibleForTesting
public static void postOnUiThreadDelayed(Runnable task, long delayMillis) {
getUiThreadHandler().postDelayed(task, delayMillis);
}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index 7dc015d..9dc6865 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -5,7 +5,6 @@
package org.chromium.base.library_loader;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log;
@@ -15,14 +14,8 @@
import org.chromium.base.JNINamespace;
import org.chromium.base.TraceEvent;
import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.HashMap;
import java.util.Locale;
import javax.annotation.Nullable;
@@ -97,9 +90,6 @@
// final (like now) or be protected in some way (volatile of synchronized).
private final int mLibraryProcessType;
- // Library -> Path it has been loaded from.
- private final HashMap<String, String> mLoadedFrom;
-
/**
* @param libraryProcessType the process the shared library is loaded in. refer to
* LibraryProcessType for possible values.
@@ -119,7 +109,6 @@
private LibraryLoader(int libraryProcessType) {
mLibraryProcessType = libraryProcessType;
- mLoadedFrom = new HashMap<String, String>();
}
/**
@@ -204,43 +193,10 @@
}
}
- private void prefetchLibraryToMemory(Context context, String library) {
- String libFilePath = mLoadedFrom.get(library);
- if (libFilePath == null) {
- Log.i(TAG, "File path not found for " + library);
- return;
- }
- String apkFilePath = context.getApplicationInfo().sourceDir;
- if (libFilePath.equals(apkFilePath)) {
- // TODO(lizeb): Make pre-faulting work with libraries loaded from the APK.
- return;
- }
- try {
- TraceEvent.begin("LibraryLoader.prefetchLibraryToMemory");
- File file = new File(libFilePath);
- int size = (int) file.length();
- FileChannel channel = new RandomAccessFile(file, "r").getChannel();
- MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
- // TODO(lizeb): Figure out whether walking the entire library is really necessary.
- // Page size is 4096 for all current Android architectures.
- for (int index = 0; index < size; index += 4096) {
- // Note: Testing shows that neither the Java compiler nor
- // Dalvik/ART eliminates this loop.
- buffer.get(index);
- }
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Library file not found: " + e);
- } catch (IOException e) {
- Log.w(TAG, "Impossible to map the file: " + e);
- } finally {
- TraceEvent.end("LibraryLoader.prefetchLibraryToMemory");
- }
- }
-
/** Prefetches the native libraries in a background thread.
*
- * Launches an AsyncTask that maps the native libraries into memory, reads a
- * part of each page from it, than unmaps it. This is done to warm up the
+ * Launches an AsyncTask that, through a short-lived forked process, reads a
+ * part of each page of the native library. This is done to warm up the
* page cache, turning hard page faults into soft ones.
*
* This is done this way, as testing shows that fadvise(FADV_WILLNEED) is
@@ -252,15 +208,13 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- // Note: AsyncTasks are executed in a low priority background
- // thread, which is the desired behavior here since we don't
- // want to interfere with the rest of the initialization.
- for (String library : NativeLibraries.LIBRARIES) {
- if (Linker.isChromiumLinkerLibrary(library)) {
- continue;
- }
- prefetchLibraryToMemory(context, library);
+ TraceEvent.begin("LibraryLoader.asyncPrefetchLibrariesToMemory");
+ boolean success = nativeForkAndPrefetchNativeLibrary();
+ if (!success) {
+ Log.w(TAG, "Forking a process to prefetch the native library failed.");
}
+ RecordHistogram.recordBooleanHistogram("LibraryLoader.PrefetchStatus", success);
+ TraceEvent.end("LibraryLoader.asyncPrefetchLibrariesToMemory");
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -340,7 +294,6 @@
? "using no map executable support fallback"
: "directly")
+ " from within " + apkFilePath);
- mLoadedFrom.put(library, apkFilePath);
} else {
// Unpack library fallback.
Log.i(TAG, "Loading " + library
@@ -350,19 +303,10 @@
context, library);
fallbackWasUsed = true;
Log.i(TAG, "Built fallback library " + libFilePath);
- mLoadedFrom.put(library, libFilePath);
}
} else {
// The library is in its own file.
Log.i(TAG, "Loading " + library);
- if (context != null) {
- ApplicationInfo applicationInfo = context.getApplicationInfo();
- File file = new File(applicationInfo.nativeLibraryDir, libFilePath);
- mLoadedFrom.put(library, file.getAbsolutePath());
- } else {
- Log.i(TAG, "No context, cannot locate the native library file for "
- + library);
- }
}
// Load the library.
@@ -580,4 +524,9 @@
// Get the version of the native library. This is needed so that we can check we
// have the right version before initializing the (rest of the) JNI.
private native String nativeGetVersionNumber();
+
+ // Finds the ranges corresponding to the native library pages, forks a new
+ // process to prefetch these pages and waits for it. The new process then
+ // terminates. This is blocking.
+ private static native boolean nativeForkAndPrefetchNativeLibrary();
}
diff --git a/base/android/java/templates/NativeLibraries.template b/base/android/java/templates/NativeLibraries.template
index d9f6a55..8b812a6 100644
--- a/base/android/java/templates/NativeLibraries.template
+++ b/base/android/java/templates/NativeLibraries.template
@@ -74,7 +74,7 @@
// array defined, and then the build system creates a version of the file
// with the real list of libraries required (which changes based upon which
// .apk is being built).
- // TODO(cjhopman): This is public since it is referenced by ChromeNativeTestActivity.java
+ // TODO(cjhopman): This is public since it is referenced by NativeTestActivity.java
// directly. The two ways of library loading should be refactored into one.
public static final String[] LIBRARIES =
#if defined(NATIVE_LIBRARIES_LIST)
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index a157354..1bbc669 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -53,7 +53,7 @@
ScopedJavaLocalRef<jintArray> ToJavaIntArray(
JNIEnv* env, const std::vector<int>& ints) {
- return ToJavaIntArray(env, ints.begin(), ints.size());
+ return ToJavaIntArray(env, ints.data(), ints.size());
}
ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
@@ -72,7 +72,7 @@
// Returns a new Java long array converted from the given int64 array.
BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
JNIEnv* env, const std::vector<int64>& longs) {
- return ToJavaLongArray(env, longs.begin(), longs.size());
+ return ToJavaLongArray(env, longs.data(), longs.size());
}
ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
index 14726fe..46bdc67 100644
--- a/base/android/junit/src/org/chromium/base/LogTest.java
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -25,9 +25,15 @@
/** Test method for {@link Log#makeTag(String)} */
@Test
public void testMakeTag() {
- assertEquals("chromium.Foo", Log.makeTag("Foo"));
- assertEquals("chromium", Log.makeTag(null));
- assertEquals("chromium", Log.makeTag(""));
+ assertEquals("cr.Foo", Log.makeTag("Foo"));
+ assertEquals("cr", Log.makeTag(null));
+ assertEquals("cr", Log.makeTag(""));
+ }
+
+ /** Test method for {@link Log#makeTag(String)} */
+ @Test(expected = IllegalArgumentException.class)
+ public void testMakeTagFailure() {
+ Log.makeTag("ThisIs21Char.....Long");
}
/** Tests that the computed call origin is the correct one. */
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
index 555420a..0b59a30 100644
--- a/base/android/library_loader/library_loader_hooks.cc
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -7,6 +7,7 @@
#include "base/android/command_line_android.h"
#include "base/android/jni_string.h"
#include "base/android/library_loader/library_load_from_apk_status_codes.h"
+#include "base/android/library_loader/library_prefetcher.h"
#include "base/at_exit.h"
#include "base/metrics/histogram.h"
#include "jni/LibraryLoader_jni.h"
@@ -122,6 +123,10 @@
}
}
+static jboolean ForkAndPrefetchNativeLibrary(JNIEnv* env, jclass clazz) {
+ return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
+}
+
bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
return RegisterNativesImpl(env);
}
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
new file mode 100644
index 0000000..798a283
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -0,0 +1,150 @@
+// Copyright 2015 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/library_loader/library_prefetcher.h"
+
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+// Android defines the background priority to this value since at least 2009
+// (see Process.java).
+const int kBackgroundPriority = 10;
+// Valid for all the Android architectures.
+const size_t kPageSize = 4096;
+const char* kLibchromeSuffix = "libchrome.so";
+// "base.apk" is a suffix because the library may be loaded directly from the
+// APK.
+const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
+
+bool IsReadableAndPrivate(const base::debug::MappedMemoryRegion& region) {
+ return region.permissions & base::debug::MappedMemoryRegion::READ &&
+ region.permissions & base::debug::MappedMemoryRegion::PRIVATE;
+}
+
+bool PathMatchesSuffix(const std::string& path) {
+ for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
+ if (EndsWith(path, kSuffixesToMatch[i], true)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// For each range, reads a byte per page to force it into the page cache.
+// Heap allocations, syscalls and library functions are not allowed in this
+// function.
+// Returns true for success.
+bool Prefetch(const std::vector<std::pair<uintptr_t, uintptr_t>>& ranges) {
+ for (const auto& range : ranges) {
+ const uintptr_t page_mask = kPageSize - 1;
+ // If start or end is not page-aligned, parsing went wrong. It is better to
+ // exit with an error.
+ if ((range.first & page_mask) || (range.second & page_mask)) {
+ return false; // CHECK() is not allowed here.
+ }
+ unsigned char* start_ptr = reinterpret_cast<unsigned char*>(range.first);
+ unsigned char* end_ptr = reinterpret_cast<unsigned char*>(range.second);
+ unsigned char dummy = 0;
+ for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
+ // Volatile is required to prevent the compiler from eliminating this
+ // loop.
+ dummy ^= *static_cast<volatile unsigned char*>(ptr);
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+bool NativeLibraryPrefetcher::IsGoodToPrefetch(
+ const base::debug::MappedMemoryRegion& region) {
+ return PathMatchesSuffix(region.path) &&
+ IsReadableAndPrivate(region); // .text and .data mappings are private.
+}
+
+// static
+void NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(
+ const std::vector<base::debug::MappedMemoryRegion>& regions,
+ std::vector<AddressRange>* ranges) {
+ bool has_libchrome_region = false;
+ for (const base::debug::MappedMemoryRegion& region : regions) {
+ if (EndsWith(region.path, kLibchromeSuffix, true)) {
+ has_libchrome_region = true;
+ break;
+ }
+ }
+ for (const base::debug::MappedMemoryRegion& region : regions) {
+ if (has_libchrome_region &&
+ !EndsWith(region.path, kLibchromeSuffix, true)) {
+ continue;
+ }
+ ranges->push_back(std::make_pair(region.start, region.end));
+ }
+}
+
+// static
+bool NativeLibraryPrefetcher::FindRanges(std::vector<AddressRange>* ranges) {
+ std::string proc_maps;
+ if (!base::debug::ReadProcMaps(&proc_maps))
+ return false;
+ std::vector<base::debug::MappedMemoryRegion> regions;
+ if (!base::debug::ParseProcMaps(proc_maps, ®ions))
+ return false;
+
+ std::vector<base::debug::MappedMemoryRegion> regions_to_prefetch;
+ for (const auto& region : regions) {
+ if (IsGoodToPrefetch(region)) {
+ regions_to_prefetch.push_back(region);
+ }
+ }
+
+ FilterLibchromeRangesOnlyIfPossible(regions_to_prefetch, ranges);
+ return true;
+}
+
+// static
+bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
+ // Looking for ranges is done before the fork, to avoid syscalls and/or memory
+ // allocations in the forked process. The child process inherits the lock
+ // state of its parent thread. It cannot rely on being able to acquire any
+ // lock (unless special care is taken in a pre-fork handler), including being
+ // able to call malloc().
+ std::vector<AddressRange> ranges;
+ if (!FindRanges(&ranges))
+ return false;
+ pid_t pid = fork();
+ if (pid == 0) {
+ setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
+ // _exit() doesn't call the atexit() handlers.
+ _exit(Prefetch(ranges) ? 0 : 1);
+ } else {
+ if (pid < 0) {
+ return false;
+ }
+ int status;
+ const pid_t result = HANDLE_EINTR(waitpid(pid, &status, 0));
+ if (result == pid) {
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status) == 0;
+ }
+ }
+ return false;
+ }
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h
new file mode 100644
index 0000000..64e5e1e
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.h
@@ -0,0 +1,67 @@
+// Copyright 2015 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_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+
+#include <jni.h>
+
+#include <stdint.h>
+#include <string>
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace android {
+
+// Forks and waits for a process prefetching the native library. This is done in
+// a forked process for the following reasons:
+// - Isolating the main process from mistakes in the parsing. If the parsing
+// returns an incorrect address, only the forked process will crash.
+// - Not inflating the memory used by the main process uselessly, which could
+// increase its likelihood to be killed.
+// The forked process has background priority and, since it is not declared to
+// the Android runtime, can be killed at any time, which is not an issue here.
+class BASE_EXPORT NativeLibraryPrefetcher {
+ public:
+ // Finds the ranges matching the native library, forks a low priority
+ // process pre-fetching these ranges and wait()s for it.
+ // Returns true for success.
+ static bool ForkAndPrefetchNativeLibrary();
+
+ private:
+ using AddressRange = std::pair<uintptr_t, uintptr_t>;
+ // Returns true if the region matches native code or data.
+ static bool IsGoodToPrefetch(const base::debug::MappedMemoryRegion& region);
+ // Filters the regions to keep only libchrome ranges if possible.
+ static void FilterLibchromeRangesOnlyIfPossible(
+ const std::vector<base::debug::MappedMemoryRegion>& regions,
+ std::vector<AddressRange>* ranges);
+ // Finds the ranges matching the native library in /proc/self/maps.
+ // Returns true for success.
+ static bool FindRanges(std::vector<AddressRange>* ranges);
+
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchNoRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchUnreadableRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchSkipSharedRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchLibchromeRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchBaseApkRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NativeLibraryPrefetcher);
+};
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
diff --git a/base/android/library_loader/library_prefetcher_unittest.cc b/base/android/library_loader/library_prefetcher_unittest.cc
new file mode 100644
index 0000000..7b7296f
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 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/library_loader/library_prefetcher.h"
+
+#include <string>
+#include <vector>
+#include "base/debug/proc_maps_linux.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+const uint8 kRead = base::debug::MappedMemoryRegion::READ;
+const uint8 kReadPrivate = base::debug::MappedMemoryRegion::READ |
+ base::debug::MappedMemoryRegion::PRIVATE;
+const uint8 kExecutePrivate = base::debug::MappedMemoryRegion::EXECUTE |
+ base::debug::MappedMemoryRegion::PRIVATE;
+} // namespace
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchNoRange) {
+ const base::debug::MappedMemoryRegion regions[4] = {
+ base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, ""},
+ base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, "foo"},
+ base::debug::MappedMemoryRegion{
+ 0x4000, 0x5000, 10, kReadPrivate, "foobar.apk"},
+ base::debug::MappedMemoryRegion{
+ 0x4000, 0x5000, 10, kReadPrivate, "libchromium.so"}};
+ for (int i = 0; i < 4; ++i) {
+ ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(regions[i]));
+ }
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchUnreadableRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kExecutePrivate, "base.apk"};
+ ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchSkipSharedRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kRead, "base.apk"};
+ ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchLibchromeRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kReadPrivate, "libchrome.so"};
+ ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchBaseApkRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kReadPrivate, "base.apk"};
+ ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome) {
+ std::vector<base::debug::MappedMemoryRegion> regions;
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+ std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+ NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+ &ranges);
+ EXPECT_EQ(ranges.size(), 2U);
+ EXPECT_EQ(ranges[0].first, 0x1U);
+ EXPECT_EQ(ranges[0].second, 0x2U);
+ EXPECT_EQ(ranges[1].first, 0x3U);
+ EXPECT_EQ(ranges[1].second, 0x4U);
+}
+
+TEST(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome) {
+ std::vector<base::debug::MappedMemoryRegion> regions;
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+ regions.push_back(base::debug::MappedMemoryRegion{
+ 0x6, 0x7, 0, kReadPrivate, "libchrome.so"});
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+ std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+ NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+ &ranges);
+ EXPECT_EQ(ranges.size(), 1U);
+ EXPECT_EQ(ranges[0].first, 0x6U);
+ EXPECT_EQ(ranges[0].second, 0x7U);
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/async_socket_io_handler_unittest.cc b/base/async_socket_io_handler_unittest.cc
index 2b0e3c2..721de9c 100644
--- a/base/async_socket_io_handler_unittest.cc
+++ b/base/async_socket_io_handler_unittest.cc
@@ -5,6 +5,9 @@
#include "base/async_socket_io_handler.h"
#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -104,8 +107,8 @@
TestSocketReader reader(&pair[0], -1, false, false);
pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitClosure(),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitClosure(),
base::TimeDelta::FromMilliseconds(100));
base::MessageLoop::current()->Run();
@@ -135,15 +138,15 @@
// Issue sends on an interval to satisfy the Read() requirements.
int64 milliseconds = 0;
for (int i = 0; i < kReadOperationCount; ++i) {
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
- kAsyncSocketIoTestStringLength),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
+ kAsyncSocketIoTestStringLength),
base::TimeDelta::FromMilliseconds(milliseconds));
milliseconds += 10;
}
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitClosure(),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitClosure(),
base::TimeDelta::FromMilliseconds(100 + milliseconds));
base::MessageLoop::current()->Run();
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
index 553fab6..2ab7242 100644
--- a/base/atomic_ref_count.h
+++ b/base/atomic_ref_count.h
@@ -4,9 +4,6 @@
// This is a low level implementation of atomic semantics for reference
// counting. Please use base/memory/ref_counted.h directly instead.
-//
-// The implementation includes annotations to avoid some false positives
-// when using data race detection tools.
#ifndef BASE_ATOMIC_REF_COUNT_H_
#define BASE_ATOMIC_REF_COUNT_H_
diff --git a/base/base.gyp b/base/base.gyp
index e9d3e81..80c3f10 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -438,6 +438,7 @@
'android/jni_android_unittest.cc',
'android/jni_array_unittest.cc',
'android/jni_string_unittest.cc',
+ 'android/library_loader/library_prefetcher_unittest.cc',
'android/path_utils_unittest.cc',
'android/scoped_java_ref_unittest.cc',
'android/sys_utils_unittest.cc',
@@ -463,6 +464,7 @@
'containers/hash_tables_unittest.cc',
'containers/linked_list_unittest.cc',
'containers/mru_cache_unittest.cc',
+ 'containers/scoped_ptr_hash_map_unittest.cc',
'containers/small_map_unittest.cc',
'containers/stack_container_unittest.cc',
'cpu_unittest.cc',
@@ -515,6 +517,7 @@
'mac/foundation_util_unittest.mm',
'mac/libdispatch_task_runner_unittest.cc',
'mac/mac_util_unittest.mm',
+ 'mac/memory_pressure_monitor_mac_unittest.cc',
'mac/objc_property_releaser_unittest.mm',
'mac/scoped_nsobject_unittest.mm',
'mac/scoped_objc_class_swizzler_unittest.mm',
@@ -1476,6 +1479,7 @@
'type': 'none',
'dependencies': [
'base_java',
+ '../testing/android/on_device_instrumentation.gyp:reporter_java',
],
'variables': {
'java_in_dir': '../base/test/android/javatests',
diff --git a/base/base.gypi b/base/base.gypi
index bbc3f60..4a8cd17 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -62,6 +62,8 @@
'android/library_loader/library_load_from_apk_status_codes.h',
'android/library_loader/library_loader_hooks.cc',
'android/library_loader/library_loader_hooks.h',
+ 'android/library_loader/library_prefetcher.cc',
+ 'android/library_loader/library_prefetcher.h',
'android/locale_utils.cc',
'android/locale_utils.h',
'android/memory_pressure_listener_android.cc',
@@ -290,6 +292,8 @@
'mac/mac_util.mm',
'mac/mach_logging.cc',
'mac/mach_logging.h',
+ 'mac/memory_pressure_monitor_mac.cc',
+ 'mac/memory_pressure_monitor_mac.h',
'mac/objc_property_releaser.h',
'mac/objc_property_releaser.mm',
'mac/os_crash_dumps.cc',
@@ -866,6 +870,7 @@
['include', '^mac/scoped_mach_vm\\.'],
['include', '^mac/scoped_nsautorelease_pool\\.'],
['include', '^mac/scoped_nsobject\\.'],
+ ['include', '^mac/scoped_objc_class_swizzler\\.'],
['include', '^message_loop/message_pump_mac\\.'],
['include', '^strings/sys_string_conversions_mac\\.'],
['include', '^threading/platform_thread_mac\\.'],
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
index c49b5b8..24063ad 100644
--- a/base/bind_helpers.h
+++ b/base/bind_helpers.h
@@ -129,7 +129,7 @@
// Passed() is particularly useful with PostTask() when you are transferring
// ownership of an argument into a task, but don't necessarily know if the
// task will always be executed. This can happen if the task is cancellable
-// or if it is posted to a MessageLoopProxy.
+// or if it is posted to a TaskRunner.
//
//
// SIMPLE FUNCTIONS AND UTILITIES.
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc
index fcbe23c..6d0a114 100644
--- a/base/cancelable_callback_unittest.cc
+++ b/base/cancelable_callback_unittest.cc
@@ -6,9 +6,11 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -165,12 +167,12 @@
CancelableClosure cancelable(base::Bind(&Increment,
base::Unretained(&count)));
- MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
RunLoop().RunUntilIdle();
EXPECT_EQ(1, count);
- MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
// Cancel before running the message loop.
cancelable.Cancel();
diff --git a/base/chromeos/memory_pressure_monitor_chromeos.cc b/base/chromeos/memory_pressure_monitor_chromeos.cc
index 404c515..82bc6a1 100644
--- a/base/chromeos/memory_pressure_monitor_chromeos.cc
+++ b/base/chromeos/memory_pressure_monitor_chromeos.cc
@@ -7,10 +7,11 @@
#include <fcntl.h>
#include <sys/select.h>
-#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/process_metrics.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
namespace base {
@@ -120,10 +121,9 @@
}
void MemoryPressureMonitorChromeOS::ScheduleEarlyCheck() {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind(&MemoryPressureMonitorChromeOS::CheckMemoryPressure,
- weak_ptr_factory_.GetWeakPtr()));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, Bind(&MemoryPressureMonitorChromeOS::CheckMemoryPressure,
+ weak_ptr_factory_.GetWeakPtr()));
}
MemoryPressureListener::MemoryPressureLevel
diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h
index d13c469..5ce9161 100644
--- a/base/containers/hash_tables.h
+++ b/base/containers/hash_tables.h
@@ -45,15 +45,9 @@
#undef __DEPRECATED
#endif
-#if defined(OS_ANDROID)
-#include <hash_map>
-#include <hash_set>
-#define BASE_HASH_IMPL_NAMESPACE std
-#else
#include <ext/hash_map>
#include <ext/hash_set>
#define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
-#endif
#include <string>
@@ -84,7 +78,6 @@
}
};
-#if !defined(OS_ANDROID)
// The GNU C++ library provides identity hash functions for many integral types,
// but not for |long long|. This hash function will truncate if |size_t| is
// narrower than |long long|. This is probably good enough for what we will
@@ -102,7 +95,6 @@
DEFINE_TRIVIAL_HASH(unsigned long long);
#undef DEFINE_TRIVIAL_HASH
-#endif // !defined(OS_ANDROID)
// Implement string hash functions so that strings of various flavors can
// be used as keys in STL maps and sets. The hash algorithm comes from the
diff --git a/base/containers/scoped_ptr_hash_map.h b/base/containers/scoped_ptr_hash_map.h
index dedf213..8fe550e 100644
--- a/base/containers/scoped_ptr_hash_map.h
+++ b/base/containers/scoped_ptr_hash_map.h
@@ -16,12 +16,12 @@
namespace base {
-// This type acts like a hash_map<K, scoped_ptr<V> >, based on top of
+// This type acts like a hash_map<K, scoped_ptr<V, D> >, based on top of
// base::hash_map. The ScopedPtrHashMap has ownership of all values in the data
// structure.
-template <typename Key, typename Value>
+template <typename Key, typename ScopedPtr>
class ScopedPtrHashMap {
- typedef base::hash_map<Key, Value*> Container;
+ typedef base::hash_map<Key, typename ScopedPtr::element_type*> Container;
public:
typedef typename Container::key_type key_type;
@@ -34,15 +34,17 @@
~ScopedPtrHashMap() { clear(); }
- void swap(ScopedPtrHashMap<Key, Value>& other) {
+ void swap(ScopedPtrHashMap<Key, ScopedPtr>& other) {
data_.swap(other.data_);
}
// Replaces value but not key if key is already present.
- iterator set(const Key& key, scoped_ptr<Value> data) {
+ iterator set(const Key& key, ScopedPtr data) {
iterator it = find(key);
if (it != end()) {
- delete it->second;
+ // Let ScopedPtr decide how to delete. For example, it may use custom
+ // deleter.
+ ScopedPtr(it->second).reset();
it->second = data.release();
return it;
}
@@ -51,7 +53,7 @@
}
// Does nothing if key is already present
- std::pair<iterator, bool> add(const Key& key, scoped_ptr<Value> data) {
+ std::pair<iterator, bool> add(const Key& key, ScopedPtr data) {
std::pair<iterator, bool> result =
data_.insert(std::make_pair(key, data.get()));
if (result.second)
@@ -60,7 +62,8 @@
}
void erase(iterator it) {
- delete it->second;
+ // Let ScopedPtr decide how to delete.
+ ScopedPtr(it->second).reset();
data_.erase(it);
}
@@ -72,45 +75,45 @@
return 1;
}
- scoped_ptr<Value> take(iterator it) {
+ ScopedPtr take(iterator it) {
DCHECK(it != data_.end());
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
- scoped_ptr<Value> ret(it->second);
+ ScopedPtr ret(it->second);
it->second = NULL;
return ret.Pass();
}
- scoped_ptr<Value> take(const Key& k) {
+ ScopedPtr take(const Key& k) {
iterator it = find(k);
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
return take(it);
}
- scoped_ptr<Value> take_and_erase(iterator it) {
+ ScopedPtr take_and_erase(iterator it) {
DCHECK(it != data_.end());
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
- scoped_ptr<Value> ret(it->second);
+ ScopedPtr ret(it->second);
data_.erase(it);
return ret.Pass();
}
- scoped_ptr<Value> take_and_erase(const Key& k) {
+ ScopedPtr take_and_erase(const Key& k) {
iterator it = find(k);
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
return take_and_erase(it);
}
// Returns the element in the hash_map that matches the given key.
// If no such element exists it returns NULL.
- Value* get(const Key& k) const {
+ typename ScopedPtr::element_type* get(const Key& k) const {
const_iterator it = find(k);
if (it == end())
return NULL;
@@ -119,7 +122,19 @@
inline bool contains(const Key& k) const { return data_.count(k) > 0; }
- inline void clear() { STLDeleteValues(&data_); }
+ inline void clear() {
+ auto it = data_.begin();
+ while (it != data_.end()) {
+ // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+ // Deleting the value does not always invalidate the iterator, but it may
+ // do so if the key is a pointer into the value object.
+ auto temp = it;
+ ++it;
+ // Let ScopedPtr decide how to delete.
+ ScopedPtr(temp->second).reset();
+ }
+ data_.clear();
+ }
inline const_iterator find(const Key& k) const { return data_.find(k); }
inline iterator find(const Key& k) { return data_.find(k); }
diff --git a/base/containers/scoped_ptr_hash_map_unittest.cc b/base/containers/scoped_ptr_hash_map_unittest.cc
new file mode 100644
index 0000000..88fe41f
--- /dev/null
+++ b/base/containers/scoped_ptr_hash_map_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2015 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/containers/scoped_ptr_hash_map.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct DeleteCounter {
+ public:
+ DeleteCounter() {}
+ ~DeleteCounter() { g_delete_count++; }
+
+ static void ResetCounter() { g_delete_count = 0; }
+ static int delete_count() { return g_delete_count; }
+
+ private:
+ static int g_delete_count;
+};
+
+int DeleteCounter::g_delete_count = 0;
+
+struct CountingDeleter {
+ public:
+ inline void operator()(DeleteCounter* ptr) const {
+ g_deleter_call_count++;
+ delete ptr;
+ }
+
+ static int count() { return g_deleter_call_count; }
+ static void ResetCounter() { g_deleter_call_count = 0; }
+
+ private:
+ static int g_deleter_call_count;
+};
+
+int CountingDeleter::g_deleter_call_count = 0;
+
+TEST(ScopedPtrHashMapTest, CustomDeleter) {
+ int key = 123;
+
+ // Test dtor.
+ DeleteCounter::ResetCounter();
+ CountingDeleter::ResetCounter();
+ {
+ ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ }
+ EXPECT_EQ(1, DeleteCounter::delete_count());
+ EXPECT_EQ(1, CountingDeleter::count());
+
+ // Test set and erase.
+ DeleteCounter::ResetCounter();
+ CountingDeleter::ResetCounter();
+ {
+ ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+ map.erase(map.set(
+ key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter)));
+ EXPECT_EQ(1, DeleteCounter::delete_count());
+ EXPECT_EQ(1, CountingDeleter::count());
+ }
+ EXPECT_EQ(1, DeleteCounter::delete_count());
+ EXPECT_EQ(1, CountingDeleter::count());
+
+ // Test set more than once.
+ DeleteCounter::ResetCounter();
+ CountingDeleter::ResetCounter();
+ {
+ ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ EXPECT_EQ(2, DeleteCounter::delete_count());
+ EXPECT_EQ(2, CountingDeleter::count());
+ }
+ EXPECT_EQ(3, DeleteCounter::delete_count());
+ EXPECT_EQ(3, CountingDeleter::count());
+}
+
+} // namespace
+} // namespace base
diff --git a/base/critical_closure.h b/base/critical_closure.h
index ac07911..75e3704 100644
--- a/base/critical_closure.h
+++ b/base/critical_closure.h
@@ -52,7 +52,7 @@
// returned.
//
// Example:
-// file_message_loop_proxy_->PostTask(
+// file_task_runner_->PostTask(
// FROM_HERE,
// MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
//
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
index 3591fd6..19df8cb 100644
--- a/base/debug/task_annotator.cc
+++ b/base/debug/task_annotator.cc
@@ -28,7 +28,6 @@
void TaskAnnotator::RunTask(const char* queue_function,
const char* run_function,
const PendingTask& pending_task) {
- tracked_objects::ThreadData::PrepareForStartOfRun(pending_task.birth_tally);
tracked_objects::TaskStopwatch stopwatch;
stopwatch.Start();
tracked_objects::Duration queue_duration =
diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc
index 81f2a0a..6e17ad9 100644
--- a/base/deferred_sequenced_task_runner_unittest.cc
+++ b/base/deferred_sequenced_task_runner_unittest.cc
@@ -7,9 +7,9 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -58,11 +58,9 @@
}
protected:
- DeferredSequencedTaskRunnerTest() :
- loop_(),
- runner_(
- new base::DeferredSequencedTaskRunner(loop_.message_loop_proxy())) {
- }
+ DeferredSequencedTaskRunnerTest()
+ : loop_(),
+ runner_(new base::DeferredSequencedTaskRunner(loop_.task_runner())) {}
base::MessageLoop loop_;
scoped_refptr<base::DeferredSequencedTaskRunner> runner_;
@@ -126,21 +124,18 @@
thread1.Start();
thread2.Start();
for (int i = 0; i < 5; ++i) {
- thread1.message_loop()->PostTask(
+ thread1.task_runner()->PostTask(
FROM_HERE,
base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
- base::Unretained(this),
- 2 * i));
- thread2.message_loop()->PostTask(
+ base::Unretained(this), 2 * i));
+ thread2.task_runner()->PostTask(
FROM_HERE,
base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
- base::Unretained(this),
- 2 * i + 1));
+ base::Unretained(this), 2 * i + 1));
if (i == 2) {
- thread1.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
- base::Unretained(this)));
+ thread1.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
+ base::Unretained(this)));
}
}
}
@@ -154,8 +149,7 @@
{
base::Thread thread("DeferredSequencedTaskRunnerTestThread");
thread.Start();
- runner_ =
- new base::DeferredSequencedTaskRunner(thread.message_loop_proxy());
+ runner_ = new base::DeferredSequencedTaskRunner(thread.task_runner());
for (int i = 0; i < 5; ++i) {
{
// Use a block to ensure that no reference to |short_lived_object|
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
index a18dbbd..e677838 100644
--- a/base/file_version_info_mac.h
+++ b/base/file_version_info_mac.h
@@ -5,16 +5,13 @@
#ifndef BASE_FILE_VERSION_INFO_MAC_H_
#define BASE_FILE_VERSION_INFO_MAC_H_
+#include <CoreFoundation/CoreFoundation.h>
#include <string>
#include "base/file_version_info.h"
#include "base/mac/scoped_nsobject.h"
-#ifdef __OBJC__
@class NSBundle;
-#else
-class NSBundle;
-#endif
class FileVersionInfoMac : public FileVersionInfo {
public:
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
index d26fa06..4f132af 100644
--- a/base/files/file_path_watcher.h
+++ b/base/files/file_path_watcher.h
@@ -12,7 +12,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
namespace base {
@@ -58,12 +58,13 @@
// check |is_cancelled()| to avoid duplicate work.
virtual void CancelOnMessageLoopThread() = 0;
- scoped_refptr<base::MessageLoopProxy> message_loop() const {
- return message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+ return task_runner_;
}
- void set_message_loop(const scoped_refptr<base::MessageLoopProxy>& loop) {
- message_loop_ = loop;
+ void set_task_runner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ task_runner_ = task_runner.Pass();
}
// Must be called before the PlatformDelegate is deleted.
@@ -76,7 +77,7 @@
}
private:
- scoped_refptr<base::MessageLoopProxy> message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
bool cancelled_;
};
diff --git a/base/files/file_path_watcher_fsevents.cc b/base/files/file_path_watcher_fsevents.cc
index ef4e6ee..da01c43 100644
--- a/base/files/file_path_watcher_fsevents.cc
+++ b/base/files/file_path_watcher_fsevents.cc
@@ -13,6 +13,7 @@
#include "base/mac/libdispatch_task_runner.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
namespace base {
@@ -92,7 +93,7 @@
if (!recursive)
return false;
- set_message_loop(MessageLoopProxy::current());
+ set_task_runner(ThreadTaskRunnerHandle::Get());
callback_ = callback;
FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
@@ -152,7 +153,7 @@
}
FilePathWatcherFSEvents::~FilePathWatcherFSEvents() {
- // This method may be called on either the libdispatch or message_loop()
+ // This method may be called on either the libdispatch or task_runner()
// thread. Checking callback_ on the libdispatch thread here is safe because
// it is executing in a task posted by Cancel() which first reset callback_.
// PostTask forms a sufficient memory barrier to ensure that the value is
@@ -165,7 +166,7 @@
const std::vector<FilePath>& paths) {
DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
DCHECK(!resolved_target_.empty());
- message_loop()->PostTask(
+ task_runner()->PostTask(
FROM_HERE, Bind(&FilePathWatcherFSEvents::DispatchEvents, this, paths,
target_, resolved_target_));
}
@@ -173,7 +174,7 @@
void FilePathWatcherFSEvents::DispatchEvents(const std::vector<FilePath>& paths,
const FilePath& target,
const FilePath& resolved_target) {
- DCHECK(message_loop()->RunsTasksOnCurrentThread());
+ DCHECK(task_runner()->RunsTasksOnCurrentThread());
// Don't issue callbacks after Cancel() has been called.
if (is_cancelled() || callback_.is_null()) {
@@ -190,7 +191,7 @@
void FilePathWatcherFSEvents::CancelOnMessageLoopThread() {
// For all other implementations, the "message loop thread" is the IO thread,
- // as returned by message_loop(). This implementation, however, needs to
+ // as returned by task_runner(). This implementation, however, needs to
// cancel pending work on the Dispatch Queue thread.
DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
@@ -239,7 +240,7 @@
g_task_runner.Get().GetDispatchQueue());
if (!FSEventStreamStart(fsevent_stream_)) {
- message_loop()->PostTask(
+ task_runner()->PostTask(
FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
}
}
@@ -250,14 +251,14 @@
bool changed = resolved != resolved_target_;
resolved_target_ = resolved;
if (resolved_target_.empty()) {
- message_loop()->PostTask(
+ task_runner()->PostTask(
FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
}
return changed;
}
void FilePathWatcherFSEvents::ReportError(const FilePath& target) {
- DCHECK(message_loop()->RunsTasksOnCurrentThread());
+ DCHECK(task_runner()->RunsTasksOnCurrentThread());
if (!callback_.is_null()) {
callback_.Run(target, true);
}
diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
index 8941d2e..e15cba7 100644
--- a/base/files/file_path_watcher_kqueue.cc
+++ b/base/files/file_path_watcher_kqueue.cc
@@ -11,6 +11,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
// On some platforms these are not defined.
#if !defined(EV_RECEIPT)
@@ -327,7 +328,7 @@
target_ = path;
MessageLoop::current()->AddDestructionObserver(this);
- io_message_loop_ = base::MessageLoopProxy::current();
+ io_task_runner_ = ThreadTaskRunnerHandle::Get();
kqueue_ = kqueue();
if (kqueue_ == -1) {
@@ -356,14 +357,14 @@
}
void FilePathWatcherKQueue::Cancel() {
- base::MessageLoopProxy* proxy = io_message_loop_.get();
- if (!proxy) {
+ SingleThreadTaskRunner* task_runner = io_task_runner_.get();
+ if (!task_runner) {
set_cancelled();
return;
}
- if (!proxy->BelongsToCurrentThread()) {
- proxy->PostTask(FROM_HERE,
- base::Bind(&FilePathWatcherKQueue::Cancel, this));
+ if (!task_runner->BelongsToCurrentThread()) {
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&FilePathWatcherKQueue::Cancel, this));
return;
}
CancelOnMessageLoopThread();
@@ -380,7 +381,7 @@
kqueue_ = -1;
std::for_each(events_.begin(), events_.end(), ReleaseEvent);
events_.clear();
- io_message_loop_ = NULL;
+ io_task_runner_ = NULL;
MessageLoop::current()->RemoveDestructionObserver(this);
callback_.Reset();
}
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h
index 87af891..69555a3 100644
--- a/base/files/file_path_watcher_kqueue.h
+++ b/base/files/file_path_watcher_kqueue.h
@@ -11,7 +11,7 @@
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
namespace base {
@@ -59,7 +59,7 @@
typedef std::vector<struct kevent> EventVector;
- // Can only be called on |io_message_loop_|'s thread.
+ // Can only be called on |io_task_runner_|'s thread.
void CancelOnMessageLoopThread() override;
// Returns true if the kevent values are error free.
@@ -118,7 +118,7 @@
}
EventVector events_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
FilePathWatcher::Callback callback_;
FilePath target_;
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index 06c517a..ba2f1d9 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -26,10 +26,10 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/trace_event/trace_event.h"
@@ -264,7 +264,7 @@
shutdown_pipe_[0] = -1;
shutdown_pipe_[1] = -1;
if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
- thread_.message_loop()->PostTask(
+ thread_.task_runner()->PostTask(
FROM_HERE,
Bind(&InotifyReaderCallback, this, inotify_fd_, shutdown_pipe_[0]));
valid_ = true;
@@ -349,12 +349,11 @@
bool created,
bool deleted,
bool is_dir) {
- if (!message_loop()->BelongsToCurrentThread()) {
- // Switch to message_loop() to access |watches_| safely.
- message_loop()->PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
- fired_watch, child, created, deleted, is_dir));
+ if (!task_runner()->BelongsToCurrentThread()) {
+ // Switch to task_runner() to access |watches_| safely.
+ task_runner()->PostTask(FROM_HERE,
+ Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
+ fired_watch, child, created, deleted, is_dir));
return;
}
@@ -452,7 +451,7 @@
DCHECK(target_.empty());
DCHECK(MessageLoopForIO::current());
- set_message_loop(MessageLoopProxy::current());
+ set_task_runner(ThreadTaskRunnerHandle::Get());
callback_ = callback;
target_ = path;
recursive_ = recursive;
@@ -476,17 +475,16 @@
}
// Switch to the message_loop() if necessary so we can access |watches_|.
- if (!message_loop()->BelongsToCurrentThread()) {
- message_loop()->PostTask(FROM_HERE,
- Bind(&FilePathWatcher::CancelWatch,
- make_scoped_refptr(this)));
+ if (!task_runner()->BelongsToCurrentThread()) {
+ task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+ make_scoped_refptr(this)));
} else {
CancelOnMessageLoopThread();
}
}
void FilePathWatcherImpl::CancelOnMessageLoopThread() {
- DCHECK(message_loop()->BelongsToCurrentThread());
+ DCHECK(task_runner()->BelongsToCurrentThread());
set_cancelled();
if (!callback_.is_null()) {
@@ -510,7 +508,7 @@
void FilePathWatcherImpl::UpdateWatches() {
// Ensure this runs on the message_loop() exclusively in order to avoid
// concurrency issues.
- DCHECK(message_loop()->BelongsToCurrentThread());
+ DCHECK(task_runner()->BelongsToCurrentThread());
DCHECK(HasValidWatchVector());
// Walk the list of watches and update them as we go.
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
index 0e1c467..21e9dd1 100644
--- a/base/files/file_path_watcher_unittest.cc
+++ b/base/files/file_path_watcher_unittest.cc
@@ -20,14 +20,15 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_file_util.h"
#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,14 +47,13 @@
class NotificationCollector
: public base::RefCountedThreadSafe<NotificationCollector> {
public:
- NotificationCollector()
- : loop_(base::MessageLoopProxy::current()) {}
+ NotificationCollector() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
// Called from the file thread by the delegates.
void OnChange(TestDelegate* delegate) {
- loop_->PostTask(FROM_HERE,
- base::Bind(&NotificationCollector::RecordChange, this,
- base::Unretained(delegate)));
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&NotificationCollector::RecordChange, this,
+ base::Unretained(delegate)));
}
void Register(TestDelegate* delegate) {
@@ -74,13 +74,13 @@
void RecordChange(TestDelegate* delegate) {
// Warning: |delegate| is Unretained. Do not dereference.
- ASSERT_TRUE(loop_->BelongsToCurrentThread());
+ ASSERT_TRUE(task_runner_->BelongsToCurrentThread());
ASSERT_TRUE(delegates_.count(delegate));
signaled_.insert(delegate);
// Check whether all delegates have been signaled.
if (signaled_ == delegates_)
- loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+ task_runner_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
}
// Set of registered delegates.
@@ -90,7 +90,7 @@
std::set<TestDelegate*> signaled_;
// The loop we should break after all delegates signaled.
- scoped_refptr<base::MessageLoopProxy> loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> {
@@ -171,7 +171,7 @@
void TearDown() override { RunLoop().RunUntilIdle(); }
void DeleteDelegateOnFileThread(TestDelegate* delegate) {
- file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, delegate);
+ file_thread_.task_runner()->DeleteSoon(FROM_HERE, delegate);
}
FilePath test_file() {
@@ -216,10 +216,9 @@
bool recursive_watch) {
base::WaitableEvent completion(false, false);
bool result;
- file_thread_.message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(SetupWatchCallback, target, watcher, delegate, recursive_watch,
- &result, &completion));
+ file_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(SetupWatchCallback, target, watcher, delegate,
+ recursive_watch, &result, &completion));
completion.Wait();
return result;
}
@@ -289,7 +288,8 @@
void OnFileChanged(const FilePath&, bool) override {
watcher_.reset();
- loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+ loop_->task_runner()->PostTask(FROM_HERE,
+ MessageLoop::QuitWhenIdleClosure());
}
FilePathWatcher* watcher() const { return watcher_.get(); }
@@ -324,7 +324,7 @@
FilePathWatcher* watcher = new FilePathWatcher;
ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false));
ASSERT_TRUE(WriteFile(test_file(), "content"));
- file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
+ file_thread_.task_runner()->DeleteSoon(FROM_HERE, watcher);
DeleteDelegateOnFileThread(delegate.release());
}
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
index d7ce524..081698f 100644
--- a/base/files/file_path_watcher_win.cc
+++ b/base/files/file_path_watcher_win.cc
@@ -10,7 +10,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/win/object_watcher.h"
@@ -57,7 +57,7 @@
// Destroy the watch handle.
void DestroyWatch();
- // Cleans up and stops observing the |message_loop_| thread.
+ // Cleans up and stops observing the |task_runner_| thread.
void CancelOnMessageLoopThread() override;
// Callback to notify upon changes.
@@ -91,7 +91,7 @@
const FilePathWatcher::Callback& callback) {
DCHECK(target_.value().empty()); // Can only watch one path.
- set_message_loop(MessageLoopProxy::current());
+ set_task_runner(ThreadTaskRunnerHandle::Get());
callback_ = callback;
target_ = path;
recursive_watch_ = recursive;
@@ -113,23 +113,22 @@
void FilePathWatcherImpl::Cancel() {
if (callback_.is_null()) {
- // Watch was never called, or the |message_loop_| has already quit.
+ // Watch was never called, or the |task_runner_| has already quit.
set_cancelled();
return;
}
// Switch to the file thread if necessary so we can stop |watcher_|.
- if (!message_loop()->BelongsToCurrentThread()) {
- message_loop()->PostTask(FROM_HERE,
- Bind(&FilePathWatcher::CancelWatch,
- make_scoped_refptr(this)));
+ if (!task_runner()->BelongsToCurrentThread()) {
+ task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+ make_scoped_refptr(this)));
} else {
CancelOnMessageLoopThread();
}
}
void FilePathWatcherImpl::CancelOnMessageLoopThread() {
- DCHECK(message_loop()->BelongsToCurrentThread());
+ DCHECK(task_runner()->BelongsToCurrentThread());
set_cancelled();
if (handle_ != INVALID_HANDLE_VALUE)
diff --git a/base/files/file_proxy.cc b/base/files/file_proxy.cc
index 53b14fe..f995735 100644
--- a/base/files/file_proxy.cc
+++ b/base/files/file_proxy.cc
@@ -9,7 +9,6 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
diff --git a/base/files/file_proxy_unittest.cc b/base/files/file_proxy_unittest.cc
index dbf1476..df0bbc8 100644
--- a/base/files/file_proxy_unittest.cc
+++ b/base/files/file_proxy_unittest.cc
@@ -9,7 +9,6 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -79,7 +78,7 @@
}
TaskRunner* file_task_runner() const {
- return file_thread_.message_loop_proxy().get();
+ return file_thread_.task_runner().get();
}
const FilePath& test_dir_path() const { return dir_.path(); }
const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
diff --git a/base/files/file_util_proxy_unittest.cc b/base/files/file_util_proxy_unittest.cc
index 5eb6819..7408369 100644
--- a/base/files/file_util_proxy_unittest.cc
+++ b/base/files/file_util_proxy_unittest.cc
@@ -8,7 +8,6 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -40,7 +39,7 @@
protected:
TaskRunner* file_task_runner() const {
- return file_thread_.message_loop_proxy().get();
+ return file_thread_.task_runner().get();
}
const FilePath& test_dir_path() const { return dir_.path(); }
const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 47b0b09..814fc7b 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -51,6 +51,12 @@
<< " : " << message;
}
+// Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
+bool WriteScopedStringToFileAtomically(const FilePath& path,
+ scoped_ptr<std::string> data) {
+ return ImportantFileWriter::WriteFileAtomically(path, *data);
+}
+
} // namespace
// static
@@ -124,7 +130,7 @@
commit_interval_(TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)),
weak_factory_(this) {
DCHECK(CalledOnValidThread());
- DCHECK(task_runner_.get());
+ DCHECK(task_runner_);
}
ImportantFileWriter::~ImportantFileWriter() {
@@ -139,9 +145,9 @@
return timer_.IsRunning();
}
-void ImportantFileWriter::WriteNow(const std::string& data) {
+void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
DCHECK(CalledOnValidThread());
- if (data.length() > static_cast<size_t>(kint32max)) {
+ if (data->length() > static_cast<size_t>(kint32max)) {
NOTREACHED();
return;
}
@@ -149,13 +155,14 @@
if (HasPendingWrite())
timer_.Stop();
- if (!PostWriteTask(data)) {
+ auto task = Bind(&WriteScopedStringToFileAtomically, path_, Passed(&data));
+ if (!PostWriteTask(task)) {
// Posting the task to background message loop is not expected
// to fail, but if it does, avoid losing data and just hit the disk
// on the current thread.
NOTREACHED();
- WriteFileAtomically(path_, data);
+ task.Run();
}
}
@@ -173,9 +180,9 @@
void ImportantFileWriter::DoScheduledWrite() {
DCHECK(serializer_);
- std::string data;
- if (serializer_->SerializeData(&data)) {
- WriteNow(data);
+ scoped_ptr<std::string> data(new std::string);
+ if (serializer_->SerializeData(data.get())) {
+ WriteNow(data.Pass());
} else {
DLOG(WARNING) << "failed to serialize data to be saved in "
<< path_.value().c_str();
@@ -189,7 +196,7 @@
on_next_successful_write_ = on_next_successful_write;
}
-bool ImportantFileWriter::PostWriteTask(const std::string& data) {
+bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
// TODO(gab): This code could always use PostTaskAndReplyWithResult and let
// ForwardSuccessfulWrite() no-op if |on_next_successful_write_| is null, but
// PostTaskAndReply causes memory leaks in tests (crbug.com/371974) and
@@ -199,16 +206,13 @@
return base::PostTaskAndReplyWithResult(
task_runner_.get(),
FROM_HERE,
- MakeCriticalClosure(
- Bind(&ImportantFileWriter::WriteFileAtomically, path_, data)),
+ MakeCriticalClosure(task),
Bind(&ImportantFileWriter::ForwardSuccessfulWrite,
weak_factory_.GetWeakPtr()));
}
return task_runner_->PostTask(
FROM_HERE,
- MakeCriticalClosure(
- Bind(IgnoreResult(&ImportantFileWriter::WriteFileAtomically),
- path_, data)));
+ MakeCriticalClosure(base::Bind(IgnoreResult(task))));
}
void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index 9ead9c1..99f1a7c 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -78,7 +78,7 @@
// Save |data| to target filename. Does not block. If there is a pending write
// scheduled by ScheduleWrite, it is cancelled.
- void WriteNow(const std::string& data);
+ void WriteNow(scoped_ptr<std::string> data);
// Schedule a save to target filename. Data will be serialized and saved
// to disk after the commit interval. If another ScheduleWrite is issued
@@ -106,7 +106,7 @@
private:
// Helper method for WriteNow().
- bool PostWriteTask(const std::string& data);
+ bool PostWriteTask(const Callback<bool()>& task);
// If |result| is true and |on_next_successful_write_| is set, invokes
// |on_successful_write_| and then resets it; no-ops otherwise.
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index 98eaee8..d376cdc 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -9,9 +9,11 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -97,10 +99,10 @@
};
TEST_F(ImportantFileWriterTest, Basic) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
EXPECT_FALSE(PathExists(writer.path()));
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
- writer.WriteNow("foo");
+ writer.WriteNow(make_scoped_ptr(new std::string("foo")));
RunLoop().RunUntilIdle();
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
@@ -109,11 +111,11 @@
}
TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
EXPECT_FALSE(PathExists(writer.path()));
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
- writer.WriteNow("foo");
+ writer.WriteNow(make_scoped_ptr(new std::string("foo")));
RunLoop().RunUntilIdle();
// Confirm that the observer is invoked.
@@ -124,7 +126,7 @@
// Confirm that re-installing the observer works for another write.
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
- writer.WriteNow("bar");
+ writer.WriteNow(make_scoped_ptr(new std::string("bar")));
RunLoop().RunUntilIdle();
EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
@@ -134,7 +136,7 @@
// Confirm that writing again without re-installing the observer doesn't
// result in a notification.
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
- writer.WriteNow("baz");
+ writer.WriteNow(make_scoped_ptr(new std::string("baz")));
RunLoop().RunUntilIdle();
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
@@ -143,15 +145,14 @@
}
TEST_F(ImportantFileWriterTest, ScheduleWrite) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
EXPECT_FALSE(writer.HasPendingWrite());
DataSerializer serializer("foo");
writer.ScheduleWrite(&serializer);
EXPECT_TRUE(writer.HasPendingWrite());
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- MessageLoop::QuitWhenIdleClosure(),
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
TimeDelta::FromMilliseconds(100));
MessageLoop::current()->Run();
EXPECT_FALSE(writer.HasPendingWrite());
@@ -160,15 +161,14 @@
}
TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
EXPECT_FALSE(writer.HasPendingWrite());
DataSerializer serializer("foo");
writer.ScheduleWrite(&serializer);
EXPECT_TRUE(writer.HasPendingWrite());
writer.DoScheduledWrite();
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- MessageLoop::QuitWhenIdleClosure(),
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
TimeDelta::FromMilliseconds(100));
MessageLoop::current()->Run();
EXPECT_FALSE(writer.HasPendingWrite());
@@ -177,15 +177,14 @@
}
TEST_F(ImportantFileWriterTest, BatchingWrites) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
DataSerializer foo("foo"), bar("bar"), baz("baz");
writer.ScheduleWrite(&foo);
writer.ScheduleWrite(&bar);
writer.ScheduleWrite(&baz);
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- MessageLoop::QuitWhenIdleClosure(),
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
TimeDelta::FromMilliseconds(100));
MessageLoop::current()->Run();
ASSERT_TRUE(PathExists(writer.path()));
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index 76eaa62..ede6467 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -19,6 +19,9 @@
#include "base/strings/sys_string_conversions.h"
#include "third_party/icu/source/common/unicode/putil.h"
#include "third_party/icu/source/common/unicode/udata.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#endif
#if defined(OS_MACOSX)
#include "base/mac/foundation_util.h"
@@ -91,6 +94,7 @@
g_called_once = true;
#endif
+ bool result;
#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
// We expect to find the ICU data module alongside the current module.
FilePath data_path;
@@ -112,10 +116,10 @@
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(reinterpret_cast<void*>(addr), &err);
- return err == U_ZERO_ERROR;
+ result = (err == U_ZERO_ERROR);
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
// The ICU data is statically linked.
- return true;
+ result = true;
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
// If the ICU data directory is set, ICU won't actually load the data until
// it is needed. This can fail if the process is sandboxed at that time.
@@ -174,11 +178,22 @@
}
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+ result = (err == U_ZERO_ERROR);
#if defined(OS_WIN)
- CHECK(err == U_ZERO_ERROR); // TODO(scottmg): http://crbug.com/445616
+ CHECK(result); // TODO(scottmg): http://crbug.com/445616
#endif
- return err == U_ZERO_ERROR;
#endif
+
+// To respond to the timezone change properly, the default timezone
+// cache in ICU has to be populated on starting up.
+// TODO(jungshik): Some callers do not care about tz at all. If necessary,
+// add a boolean argument to this function to init'd the default tz only
+// when requested.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (result)
+ scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+#endif
+ return result;
}
#endif
diff --git a/base/mac/launch_services_util.h b/base/mac/launch_services_util.h
index 0c52ca9..0e64316 100644
--- a/base/mac/launch_services_util.h
+++ b/base/mac/launch_services_util.h
@@ -5,7 +5,7 @@
#ifndef BASE_MAC_LAUNCH_SERVICES_UTIL_H_
#define BASE_MAC_LAUNCH_SERVICES_UTIL_H_
-#include <ApplicationServices/ApplicationServices.h>
+#include <CoreServices/CoreServices.h>
#include "base/base_export.h"
#include "base/command_line.h"
diff --git a/base/mac/memory_pressure_monitor_mac.cc b/base/mac/memory_pressure_monitor_mac.cc
new file mode 100644
index 0000000..81727bb
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac.cc
@@ -0,0 +1,76 @@
+// Copyright 2015 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/mac/memory_pressure_monitor_mac.h"
+
+#include <dlfcn.h>
+#include <sys/sysctl.h>
+
+#include "base/mac/mac_util.h"
+
+namespace base {
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitorMac::MemoryPressureLevelForMacMemoryPressure(
+ int mac_memory_pressure) {
+ switch (mac_memory_pressure) {
+ case DISPATCH_MEMORYPRESSURE_NORMAL:
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+ case DISPATCH_MEMORYPRESSURE_WARN:
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+ case DISPATCH_MEMORYPRESSURE_CRITICAL:
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+ }
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+void MemoryPressureMonitorMac::NotifyMemoryPressureChanged(
+ dispatch_source_s* event_source) {
+ int mac_memory_pressure = dispatch_source_get_data(event_source);
+ MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
+ MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+ MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+}
+
+MemoryPressureMonitorMac::MemoryPressureMonitorMac()
+ : memory_level_event_source_(nullptr) {
+ // _dispatch_source_type_memorypressure is not available prior to 10.9.
+ dispatch_source_type_t dispatch_source_memorypressure =
+ static_cast<dispatch_source_type_t>
+ (dlsym(RTLD_NEXT, "_dispatch_source_type_memorypressure"));
+ if (dispatch_source_memorypressure) {
+ // The MemoryPressureListener doesn't want to know about transitions to
+ // MEMORY_PRESSURE_LEVEL_NONE so don't watch for
+ // DISPATCH_MEMORYPRESSURE_NORMAL notifications.
+ memory_level_event_source_.reset(
+ dispatch_source_create(dispatch_source_memorypressure, 0,
+ DISPATCH_MEMORYPRESSURE_WARN |
+ DISPATCH_MEMORYPRESSURE_CRITICAL,
+ dispatch_get_global_queue(
+ DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)));
+
+ dispatch_source_set_event_handler(memory_level_event_source_.get(), ^{
+ NotifyMemoryPressureChanged(memory_level_event_source_.get());
+ });
+ dispatch_retain(memory_level_event_source_.get());
+ dispatch_resume(memory_level_event_source_.get());
+ }
+}
+
+MemoryPressureMonitorMac::~MemoryPressureMonitorMac() {
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitorMac::GetCurrentPressureLevel() const {
+ if (base::mac::IsOSMountainLionOrEarlier()) {
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+ }
+ int mac_memory_pressure;
+ size_t length = sizeof(int);
+ sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure,
+ &length, nullptr, 0);
+ return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+}
+
+} // namespace base
diff --git a/base/mac/memory_pressure_monitor_mac.h b/base/mac/memory_pressure_monitor_mac.h
new file mode 100644
index 0000000..aebdd65
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac.h
@@ -0,0 +1,62 @@
+// Copyright 2015 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_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+
+// The following was added to <dispatch/source.h> after 10.8.
+// TODO(shrike): Remove the DISPATCH_MEMORYPRESSURE_NORMAL ifndef once builders
+// reach 10.9 or higher.
+#ifndef DISPATCH_MEMORYPRESSURE_NORMAL
+
+#define DISPATCH_MEMORYPRESSURE_NORMAL 0x01
+#define DISPATCH_MEMORYPRESSURE_WARN 0x02
+#define DISPATCH_MEMORYPRESSURE_CRITICAL 0x04
+
+#endif // DISPATCH_MEMORYPRESSURE_NORMAL
+
+namespace base {
+
+class TestMemoryPressureMonitorMac;
+
+struct DispatchSourceSDeleter {
+ void operator()(dispatch_source_s* ptr) {
+ dispatch_source_cancel(ptr);
+ dispatch_release(ptr);
+ }
+};
+
+// Declares the interface for the Mac MemoryPressureMonitor, which reports
+// memory pressure events and status.
+class BASE_EXPORT MemoryPressureMonitorMac : public MemoryPressureMonitor {
+ public:
+ using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+ MemoryPressureMonitorMac();
+ ~MemoryPressureMonitorMac() override;
+
+ // Returns the currently-observed memory pressure.
+ MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+ private:
+ friend TestMemoryPressureMonitorMac;
+
+ static MemoryPressureLevel
+ MemoryPressureLevelForMacMemoryPressure(int mac_memory_pressure);
+ static void NotifyMemoryPressureChanged(dispatch_source_s* event_source);
+
+ scoped_ptr<dispatch_source_s, DispatchSourceSDeleter>
+ memory_level_event_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitorMac);
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
diff --git a/base/mac/memory_pressure_monitor_mac_unittest.cc b/base/mac/memory_pressure_monitor_mac_unittest.cc
new file mode 100644
index 0000000..24ee09a
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 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/mac/memory_pressure_monitor_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class TestMemoryPressureMonitorMac : public MemoryPressureMonitorMac {
+ public:
+ using MemoryPressureMonitorMac::MemoryPressureLevelForMacMemoryPressure;
+
+ TestMemoryPressureMonitorMac() { }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitorMac);
+};
+
+TEST(TestMemoryPressureMonitorMac, MemoryPressureFromMacMemoryPressure) {
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitorMac::
+ MemoryPressureLevelForMacMemoryPressure(
+ DISPATCH_MEMORYPRESSURE_NORMAL));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ TestMemoryPressureMonitorMac::
+ MemoryPressureLevelForMacMemoryPressure(
+ DISPATCH_MEMORYPRESSURE_WARN));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ TestMemoryPressureMonitorMac::
+ MemoryPressureLevelForMacMemoryPressure(
+ DISPATCH_MEMORYPRESSURE_CRITICAL));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitorMac::
+ MemoryPressureLevelForMacMemoryPressure(0));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitorMac::
+ MemoryPressureLevelForMacMemoryPressure(3));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitorMac::
+ MemoryPressureLevelForMacMemoryPressure(5));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitorMac::
+ MemoryPressureLevelForMacMemoryPressure(-1));
+}
+
+TEST(TestMemoryPressureMonitorMac, CurrentMemoryPressure) {
+ TestMemoryPressureMonitorMac monitor;
+ MemoryPressureListener::MemoryPressureLevel memory_pressure =
+ monitor.GetCurrentPressureLevel();
+ EXPECT_TRUE(memory_pressure ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE ||
+ memory_pressure ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE ||
+ memory_pressure ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+}
+
+} // namespace base
diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h
index 8814b51..836bdcc 100644
--- a/base/mac/scoped_nsobject.h
+++ b/base/mac/scoped_nsobject.h
@@ -5,10 +5,16 @@
#ifndef BASE_MAC_SCOPED_NSOBJECT_H_
#define BASE_MAC_SCOPED_NSOBJECT_H_
-#import <Foundation/Foundation.h>
+// Include NSObject.h directly because Foundation.h pulls in many dependencies.
+// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
+// singled out because it is most typically included from other header files.
+#import <Foundation/NSObject.h>
+
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+@class NSAutoreleasePool;
+
namespace base {
// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 25d937e..d7be320 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -18,16 +18,91 @@
#include "base/base_export.h"
+// ----------------------------------------------------------------------------
+// Either define or forward declare classes only available in OSX 10.7+.
+// ----------------------------------------------------------------------------
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface CWChannel : NSObject
+@end
+
+@interface CBPeripheral : NSObject
+@end
+
+@interface CBCentralManager : NSObject
+@end
+
+@interface CBUUID : NSObject
+@end
+
+#else
+
+@class CWChannel;
+@class CBPeripheral;
+@class CBCentralManager;
+@class CBUUID;
+
+#endif // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+@interface NSUUID : NSObject
+@end
+
+#else
+
+@class NSUUID;
+
+#endif // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+// NSProgress is public API in 10.9, but a version of it exists and is usable
+// in 10.8.
+@interface NSProgress : NSObject
+@end
+
+@interface NSAppearance : NSObject
+@end
+
+#else
+
+@class NSProgress;
+@class NSAppearance;
+
+#endif // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity : NSObject
+@end
+
+#else
+
+@class NSUserActivity;
+
+#endif // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// Define typedefs, enums, and protocols not available in the version of the
+// OSX SDK being compiled against.
+// ----------------------------------------------------------------------------
+
#if !defined(MAC_OS_X_VERSION_10_7) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
enum {
- NSEventPhaseNone = 0, // event not associated with a phase.
- NSEventPhaseBegan = 0x1 << 0,
- NSEventPhaseStationary = 0x1 << 1,
- NSEventPhaseChanged = 0x1 << 2,
- NSEventPhaseEnded = 0x1 << 3,
- NSEventPhaseCancelled = 0x1 << 4
+ NSEventPhaseNone = 0, // event not associated with a phase.
+ NSEventPhaseBegan = 0x1 << 0,
+ NSEventPhaseStationary = 0x1 << 1,
+ NSEventPhaseChanged = 0x1 << 2,
+ NSEventPhaseEnded = 0x1 << 3,
+ NSEventPhaseCancelled = 0x1 << 4
};
typedef NSUInteger NSEventPhase;
@@ -65,9 +140,139 @@
};
typedef NSUInteger NSWindowButton;
+enum CWChannelBand {
+ kCWChannelBandUnknown = 0,
+ kCWChannelBand2GHz = 1,
+ kCWChannelBand5GHz = 2,
+};
+
+enum {
+ kCWSecurityNone = 0,
+ kCWSecurityWEP = 1,
+ kCWSecurityWPAPersonal = 2,
+ kCWSecurityWPAPersonalMixed = 3,
+ kCWSecurityWPA2Personal = 4,
+ kCWSecurityPersonal = 5,
+ kCWSecurityDynamicWEP = 6,
+ kCWSecurityWPAEnterprise = 7,
+ kCWSecurityWPAEnterpriseMixed = 8,
+ kCWSecurityWPA2Enterprise = 9,
+ kCWSecurityEnterprise = 10,
+ kCWSecurityUnknown = NSIntegerMax,
+};
+
+typedef NSInteger CWSecurity;
+
+enum {
+ kBluetoothFeatureLESupportedController = (1 << 6L),
+};
+
+@protocol IOBluetoothDeviceInquiryDelegate
+- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
+- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
+ device:(IOBluetoothDevice*)device;
+- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
+ error:(IOReturn)error
+ aborted:(BOOL)aborted;
+@end
+
+@protocol NSWindowDelegateFullScreenAdditions
+- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
+- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
+@end
+
+enum {
+ CBPeripheralStateDisconnected = 0,
+ CBPeripheralStateConnecting,
+ CBPeripheralStateConnected,
+};
+typedef NSInteger CBPeripheralState;
+
+enum {
+ CBCentralManagerStateUnknown = 0,
+ CBCentralManagerStateResetting,
+ CBCentralManagerStateUnsupported,
+ CBCentralManagerStateUnauthorized,
+ CBCentralManagerStatePoweredOff,
+ CBCentralManagerStatePoweredOn,
+};
+typedef NSInteger CBCentralManagerState;
+
+@protocol CBCentralManagerDelegate;
+
+@protocol CBCentralManagerDelegate<NSObject>
+- (void)centralManagerDidUpdateState:(CBCentralManager*)central;
+- (void)centralManager:(CBCentralManager*)central
+ didDiscoverPeripheral:(CBPeripheral*)peripheral
+ advertisementData:(NSDictionary*)advertisementData
+ RSSI:(NSNumber*)RSSI;
+@end
+
+#endif // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+enum { NSEventPhaseMayBegin = 0x1 << 5 };
+
+#endif // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+enum {
+ NSWindowOcclusionStateVisible = 1UL << 1,
+};
+typedef NSUInteger NSWindowOcclusionState;
+
+enum { NSWorkspaceLaunchWithErrorPresentation = 0x00000040 };
+
+#endif // MAC_OS_X_VERSION_10_9
+
+// ----------------------------------------------------------------------------
+// Define NSStrings only available in newer versions of the OSX SDK to force
+// them to be statically linked.
+// ----------------------------------------------------------------------------
+
+extern "C" {
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+BASE_EXPORT extern NSString* const NSWindowWillEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowWillExitFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidExitFullScreenNotification;
+BASE_EXPORT extern NSString* const
+ NSWindowDidChangeBackingPropertiesNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataServiceDataKey;
+#endif // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern NSString* const NSWindowDidChangeOcclusionStateNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataIsConnectable;
+#endif // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+BASE_EXPORT extern NSString* const NSUserActivityTypeBrowsingWeb;
+BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
+#endif // MAC_OS_X_VERSION_10_10
+} // extern "C"
+
+// ----------------------------------------------------------------------------
+// If compiling against an older version of the OSX SDK, declare functions that
+// are available in newer versions of the OSX SDK. If compiling against a newer
+// version of the OSX SDK, redeclare those same functions to suppress
+// -Wpartial-availability warnings.
+// ----------------------------------------------------------------------------
+
+// Once Chrome no longer supports OSX 10.6, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+
@interface NSEvent (LionSDK)
+ (BOOL)isSwipeTrackingFromScrollEventsEnabled;
-
- (NSEventPhase)momentumPhase;
- (NSEventPhase)phase;
- (BOOL)hasPreciseScrollingDeltas;
@@ -79,10 +284,8 @@
usingHandler:(void (^)(CGFloat gestureAmount,
NSEventPhase phase,
BOOL isComplete,
- BOOL *stop))trackingHandler;
-
+ BOOL* stop))trackingHandler;
- (BOOL)isDirectionInvertedFromDevice;
-
@end
@interface NSApplication (LionSDK)
@@ -113,9 +316,9 @@
@end
@interface NSAnimationContext (LionSDK)
-+ (void)runAnimationGroup:(void (^)(NSAnimationContext *context))changes
++ (void)runAnimationGroup:(void (^)(NSAnimationContext* context))changes
completionHandler:(void (^)(void))completionHandler;
-@property(copy) void(^completionHandler)(void);
+@property(copy) void (^completionHandler)(void);
@end
@interface NSView (LionSDK)
@@ -139,37 +342,13 @@
- (BOOL)associateToNetwork:(CWNetwork*)network
password:(NSString*)password
error:(NSError**)error;
-- (NSSet*)scanForNetworksWithName:(NSString*)networkName
- error:(NSError**)error;
+- (NSSet*)scanForNetworksWithName:(NSString*)networkName error:(NSError**)error;
@end
-enum CWChannelBand {
- kCWChannelBandUnknown = 0,
- kCWChannelBand2GHz = 1,
- kCWChannelBand5GHz = 2,
-};
-
-@interface CWChannel : NSObject
+@interface CWChannel (LionSDK)
@property(readonly) CWChannelBand channelBand;
@end
-enum {
- kCWSecurityNone = 0,
- kCWSecurityWEP = 1,
- kCWSecurityWPAPersonal = 2,
- kCWSecurityWPAPersonalMixed = 3,
- kCWSecurityWPA2Personal = 4,
- kCWSecurityPersonal = 5,
- kCWSecurityDynamicWEP = 6,
- kCWSecurityWPAEnterprise = 7,
- kCWSecurityWPAEnterpriseMixed = 8,
- kCWSecurityWPA2Enterprise = 9,
- kCWSecurityEnterprise = 10,
- kCWSecurityUnknown = NSIntegerMax,
-};
-
-typedef NSInteger CWSecurity;
-
@interface CWNetwork (LionSDK)
@property(readonly) CWChannel* wlanChannel;
@property(readonly) NSInteger rssiValue;
@@ -181,19 +360,6 @@
- (BluetoothHCIPowerState)powerState;
@end
-enum {
- kBluetoothFeatureLESupportedController = (1 << 6L),
-};
-
-@protocol IOBluetoothDeviceInquiryDelegate
-- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
-- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
- device:(IOBluetoothDevice*)device;
-- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
- error:(IOReturn)error
- aborted:(BOOL)aborted;
-@end
-
@interface IOBluetoothL2CAPChannel (LionSDK)
@property(readonly) BluetoothL2CAPMTU outgoingMTU;
@end
@@ -207,46 +373,13 @@
- (IOReturn)performSDPQuery:(id)target uuids:(NSArray*)uuids;
@end
-BASE_EXPORT extern "C" NSString* const NSWindowWillEnterFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowWillExitFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowDidEnterFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowDidExitFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const
- NSWindowDidChangeBackingPropertiesNotification;
-
-@protocol NSWindowDelegateFullScreenAdditions
-- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
-- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
-@end
-
-BASE_EXPORT extern "C" NSString* const CBAdvertisementDataServiceDataKey;
-
-enum {
- CBPeripheralStateDisconnected = 0,
- CBPeripheralStateConnecting,
- CBPeripheralStateConnected,
-};
-typedef NSInteger CBPeripheralState;
-
-@interface CBPeripheral : NSObject
+@interface CBPeripheral (LionSDK)
@property(readonly, nonatomic) CFUUIDRef UUID;
@property(retain, readonly) NSString* name;
@property(readonly) BOOL isConnected;
@end
-enum {
- CBCentralManagerStateUnknown = 0,
- CBCentralManagerStateResetting,
- CBCentralManagerStateUnsupported,
- CBCentralManagerStateUnauthorized,
- CBCentralManagerStatePoweredOff,
- CBCentralManagerStatePoweredOn,
-};
-typedef NSInteger CBCentralManagerState;
-
-@protocol CBCentralManagerDelegate;
-
-@interface CBCentralManager : NSObject
+@interface CBCentralManager (LionSDK)
@property(readonly) CBCentralManagerState state;
- (id)initWithDelegate:(id<CBCentralManagerDelegate>)delegate
queue:(dispatch_queue_t)queue;
@@ -255,33 +388,23 @@
- (void)stopScan;
@end
-@protocol CBCentralManagerDelegate<NSObject>
-- (void)centralManagerDidUpdateState:(CBCentralManager*)central;
-- (void)centralManager:(CBCentralManager*)central
- didDiscoverPeripheral:(CBPeripheral*)peripheral
- advertisementData:(NSDictionary*)advertisementData
- RSSI:(NSNumber*)RSSI;
-@end
-
-@interface CBUUID : NSObject
+@interface CBUUID (LionSDK)
@property(nonatomic, readonly) NSData* data;
+ (CBUUID*)UUIDWithString:(NSString*)theString;
@end
#endif // MAC_OS_X_VERSION_10_7
+// Once Chrome no longer supports OSX 10.7, everything within this preprocessor
+// block can be removed.
#if !defined(MAC_OS_X_VERSION_10_8) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
-
-enum {
- NSEventPhaseMayBegin = 0x1 << 5
-};
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
@interface NSColor (MountainLionSDK)
- (CGColorRef)CGColor;
@end
-@interface NSUUID : NSObject
+@interface NSUUID (MountainLionSDK)
- (NSString*)UUIDString;
@end
@@ -291,36 +414,34 @@
#endif // MAC_OS_X_VERSION_10_8
-
+// Once Chrome no longer supports OSX 10.8, everything within this preprocessor
+// block can be removed.
#if !defined(MAC_OS_X_VERSION_10_9) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
-// NSProgress is public API in 10.9, but a version of it exists and is usable
-// in 10.8.
-
-@interface NSProgress : NSObject
+@interface NSProgress (MavericksSDK)
- (instancetype)initWithParent:(NSProgress*)parentProgressOrNil
userInfo:(NSDictionary*)userInfoOrNil;
-@property (copy) NSString* kind;
+@property(copy) NSString* kind;
@property int64_t totalUnitCount;
@property int64_t completedUnitCount;
-@property (getter=isCancellable) BOOL cancellable;
-@property (getter=isPausable) BOOL pausable;
-@property (readonly, getter=isCancelled) BOOL cancelled;
-@property (readonly, getter=isPaused) BOOL paused;
-@property (copy) void (^cancellationHandler)(void);
-@property (copy) void (^pausingHandler)(void);
+@property(getter=isCancellable) BOOL cancellable;
+@property(getter=isPausable) BOOL pausable;
+@property(readonly, getter=isCancelled) BOOL cancelled;
+@property(readonly, getter=isPaused) BOOL paused;
+@property(copy) void (^cancellationHandler)(void);
+@property(copy) void (^pausingHandler)(void);
- (void)cancel;
- (void)pause;
- (void)setUserInfoObject:(id)objectOrNil forKey:(NSString*)key;
- (NSDictionary*)userInfo;
-@property (readonly, getter=isIndeterminate) BOOL indeterminate;
-@property (readonly) double fractionCompleted;
+@property(readonly, getter=isIndeterminate) BOOL indeterminate;
+@property(readonly) double fractionCompleted;
- (void)publish;
- (void)unpublish;
@@ -331,72 +452,35 @@
+ (BOOL)screensHaveSeparateSpaces;
@end
-// NSAppearance is a new class in the 10.9 SDK. New classes cannot be
-// forward-declared because they also require an @implementation, which would
-// produce conflicting linkage. Instead, just declare the necessary pieces of
-// the interface as a protocol, and treat objects of this type as id.
-@protocol CrNSAppearance<NSObject>
-+ (id<NSObject>)appearanceNamed:(NSString*)name;
-@end
-
@interface NSView (MavericksSDK)
- (void)setCanDrawSubviewsIntoLayer:(BOOL)flag;
-- (id<CrNSAppearance>)effectiveAppearance;
+- (NSAppearance*)effectiveAppearance;
@end
-enum {
- NSWindowOcclusionStateVisible = 1UL << 1,
-};
-typedef NSUInteger NSWindowOcclusionState;
-
@interface NSWindow (MavericksSDK)
- (NSWindowOcclusionState)occlusionState;
@end
-
-BASE_EXPORT extern "C" NSString* const
- NSWindowDidChangeOcclusionStateNotification;
-
-enum {
- NSWorkspaceLaunchWithErrorPresentation = 0x00000040
-};
+@interface NSAppearance (MavericksSDK)
++ (id<NSObject>)appearanceNamed:(NSString*)name;
+@end
@interface CBPeripheral (MavericksSDK)
@property(readonly, nonatomic) NSUUID* identifier;
@end
-BASE_EXPORT extern "C" NSString* const CBAdvertisementDataIsConnectable;
-
-#else // !MAC_OS_X_VERSION_10_9
-
-typedef enum {
- kCWSecurityModeOpen = 0,
- kCWSecurityModeWEP,
- kCWSecurityModeWPA_PSK,
- kCWSecurityModeWPA2_PSK,
- kCWSecurityModeWPA_Enterprise,
- kCWSecurityModeWPA2_Enterprise,
- kCWSecurityModeWPS,
- kCWSecurityModeDynamicWEP
-} CWSecurityMode;
-
-@interface CWNetwork (SnowLeopardSDK)
-@property(readonly) NSNumber* rssi;
-@property(readonly) NSNumber* securityMode;
-@end
-
-BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
-
#endif // MAC_OS_X_VERSION_10_9
+// Once Chrome no longer supports OSX 10.9, everything within this preprocessor
+// block can be removed.
#if !defined(MAC_OS_X_VERSION_10_10) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
-@interface NSUserActivity : NSObject
+@interface NSUserActivity (YosemiteSDK)
-@property (readonly, copy) NSString* activityType;
-@property (copy) NSDictionary* userInfo;
-@property (copy) NSURL* webpageURL;
+@property(readonly, copy) NSString* activityType;
+@property(copy) NSDictionary* userInfo;
+@property(copy) NSURL* webpageURL;
- (instancetype)initWithActivityType:(NSString*)activityType;
- (void)becomeCurrent;
@@ -404,14 +488,48 @@
@end
-BASE_EXPORT extern "C" NSString* const NSUserActivityTypeBrowsingWeb;
-
-BASE_EXPORT extern "C" NSString* const NSAppearanceNameVibrantDark;
-
@interface CBUUID (YosemiteSDK)
- (NSString*)UUIDString;
@end
#endif // MAC_OS_X_VERSION_10_10
+// ----------------------------------------------------------------------------
+// Chrome uses -[CWNetwork securityMode] and -[CWNetwork rssi] on OSX 10.6. The
+// former method relies on the enum CWSecurityMode which was removed in the OSX
+// 10.9 SDK. In order for Chrome to compile against an OSX 10.9+ SDK, Chrome
+// must define this enum. Chrome must also declare these methods.
+//
+// These declarations and definitions will not be necessary once Chrome no
+// longer runs on OSX 10.6.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_6
+typedef enum {
+ kCWSecurityModeOpen = 0,
+ kCWSecurityModeWEP,
+ kCWSecurityModeWPA_PSK,
+ kCWSecurityModeWPA2_PSK,
+ kCWSecurityModeWPA_Enterprise,
+ kCWSecurityModeWPA2_Enterprise,
+ kCWSecurityModeWPS,
+ kCWSecurityModeDynamicWEP
+} CWSecurityMode;
+
+@interface CWNetwork (SnowLeopardSDK)
+@property(readonly) NSNumber* rssi;
+@property(readonly) NSNumber* securityMode;
+@end
+#endif
+
+// ----------------------------------------------------------------------------
+// The symbol for kCWSSIDDidChangeNotification is available in the
+// CoreWLAN.framework for OSX versions 10.6 through 10.10. The symbol is not
+// declared in the OSX 10.9+ SDK, so when compiling against an OSX 10.9+ SDK,
+// declare the symbol.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
+#endif
#endif // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
diff --git a/base/mac/sdk_forward_declarations.mm b/base/mac/sdk_forward_declarations.mm
index 4edc710..347e87c 100644
--- a/base/mac/sdk_forward_declarations.mm
+++ b/base/mac/sdk_forward_declarations.mm
@@ -4,10 +4,8 @@
#include "base/mac/sdk_forward_declarations.h"
-// Replicate specific 10.7 SDK declarations for building with prior SDKs.
#if !defined(MAC_OS_X_VERSION_10_7) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
NSString* const NSWindowWillEnterFullScreenNotification =
@"NSWindowWillEnterFullScreenNotification";
@@ -24,27 +22,20 @@
@"NSWindowDidChangeBackingPropertiesNotification";
NSString* const CBAdvertisementDataServiceDataKey = @"kCBAdvDataServiceData";
-
#endif // MAC_OS_X_VERSION_10_7
-// Replicate specific 10.9 SDK declarations for building with prior SDKs.
#if !defined(MAC_OS_X_VERSION_10_9) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
-
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
NSString* const NSWindowDidChangeOcclusionStateNotification =
@"NSWindowDidChangeOcclusionStateNotification";
NSString* const CBAdvertisementDataIsConnectable = @"kCBAdvDataIsConnectable";
-
#endif // MAC_OS_X_VERSION_10_9
-// Replicate specific 10.10 SDK declarations for building with prior SDKs.
#if !defined(MAC_OS_X_VERSION_10_10) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
-
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
NSString* const NSUserActivityTypeBrowsingWeb =
@"NSUserActivityTypeBrowsingWeb";
NSString* const NSAppearanceNameVibrantDark = @"NSAppearanceNameVibrantDark";
-
#endif // MAC_OS_X_VERSION_10_10
diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h
index 139a1ed..6a109e8 100644
--- a/base/memory/ref_counted_delete_on_message_loop.h
+++ b/base/memory/ref_counted_delete_on_message_loop.h
@@ -32,6 +32,7 @@
// ~Foo();
// };
+// TODO(skyostil): Rename this to RefCountedDeleteOnTaskRunner.
template <class T>
class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase {
public:
@@ -42,7 +43,7 @@
RefCountedDeleteOnMessageLoop(
const scoped_refptr<SingleThreadTaskRunner>& task_runner)
: task_runner_(task_runner) {
- DCHECK(task_runner_.get());
+ DCHECK(task_runner_);
}
void AddRef() const {
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc
index d89a5c6..20e5c7b 100644
--- a/base/memory/weak_ptr_unittest.cc
+++ b/base/memory/weak_ptr_unittest.cc
@@ -8,8 +8,9 @@
#include "base/bind.h"
#include "base/debug/leak_annotations.h"
+#include "base/location.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,9 +26,8 @@
{
Thread creator_thread("creator_thread");
creator_thread.Start();
- creator_thread.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(OffThreadObjectCreator::CreateObject, &result));
+ creator_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(OffThreadObjectCreator::CreateObject, &result));
}
DCHECK(result); // We synchronized on thread destruction above.
return result;
@@ -66,25 +66,23 @@
void CreateArrowFromTarget(Arrow** arrow, Target* target) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCreateArrowFromTarget,
- arrow, target, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromTarget, arrow,
+ target, &completion));
completion.Wait();
}
void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCreateArrowFromArrow,
- arrow, other, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromArrow, arrow,
+ other, &completion));
completion.Wait();
}
void DeleteTarget(Target* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
+ task_runner()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
completion.Wait();
@@ -92,25 +90,23 @@
void CopyAndAssignArrow(Arrow* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCopyAndAssignArrow,
- object, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrow, object,
+ &completion));
completion.Wait();
}
void CopyAndAssignArrowBase(Arrow* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
- object, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
+ object, &completion));
completion.Wait();
}
void DeleteArrow(Arrow* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
+ task_runner()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
completion.Wait();
@@ -119,9 +115,8 @@
Target* DeRef(const Arrow* arrow) {
WaitableEvent completion(true, false);
Target* result = NULL;
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion));
+ task_runner()->PostTask(FROM_HERE, base::Bind(&BackgroundThread::DoDeRef,
+ arrow, &result, &completion));
completion.Wait();
return result;
}
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index c1ce939..5e9a461 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -44,7 +44,8 @@
message_loop_(message_loop),
next_sequence_num_(0),
message_loop_scheduled_(false),
- always_schedule_work_(AlwaysNotifyPump(message_loop_->type())) {
+ always_schedule_work_(AlwaysNotifyPump(message_loop_->type())),
+ is_ready_for_scheduling_(false) {
}
bool IncomingTaskQueue::AddToIncomingQueue(
@@ -109,6 +110,15 @@
message_loop_ = NULL;
}
+void IncomingTaskQueue::StartScheduling() {
+ AutoLock lock(incoming_queue_lock_);
+ DCHECK(!is_ready_for_scheduling_);
+ DCHECK(!message_loop_scheduled_);
+ is_ready_for_scheduling_ = true;
+ if (!incoming_queue_.empty())
+ ScheduleWork();
+}
+
IncomingTaskQueue::~IncomingTaskQueue() {
// Verify that WillDestroyCurrentMessageLoop() has been called.
DCHECK(!message_loop_);
@@ -148,19 +158,25 @@
incoming_queue_.push(*pending_task);
pending_task->task.Reset();
- if (always_schedule_work_ || (!message_loop_scheduled_ && was_empty)) {
- // Wake up the message loop.
- message_loop_->ScheduleWork();
- // After we've scheduled the message loop, we do not need to do so again
- // until we know it has processed all of the work in our queue and is
- // waiting for more work again. The message loop will always attempt to
- // reload from the incoming queue before waiting again so we clear this flag
- // in ReloadWorkQueue().
- message_loop_scheduled_ = true;
+ if (is_ready_for_scheduling_ &&
+ (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) {
+ ScheduleWork();
}
return true;
}
+void IncomingTaskQueue::ScheduleWork() {
+ DCHECK(is_ready_for_scheduling_);
+ // Wake up the message loop.
+ message_loop_->ScheduleWork();
+ // After we've scheduled the message loop, we do not need to do so again
+ // until we know it has processed all of the work in our queue and is
+ // waiting for more work again. The message loop will always attempt to
+ // reload from the incoming queue before waiting again so we clear this flag
+ // in ReloadWorkQueue().
+ message_loop_scheduled_ = true;
+}
+
} // namespace internal
} // namespace base
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 72e1f30..7dd1e82 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -53,6 +53,10 @@
// Disconnects |this| from the parent message loop.
void WillDestroyCurrentMessageLoop();
+ // This should be called when the message loop becomes ready for
+ // scheduling work.
+ void StartScheduling();
+
private:
friend class RefCountedThreadSafe<IncomingTaskQueue>;
virtual ~IncomingTaskQueue();
@@ -66,6 +70,9 @@
// does not retain |pending_task->task| beyond this function call.
bool PostPendingTask(PendingTask* pending_task);
+ // Wakes up the message loop and schedules work.
+ void ScheduleWork();
+
// Number of tasks that require high resolution timing. This value is kept
// so that ReloadWorkQueue() completes in constant time.
int high_res_task_count_;
@@ -92,6 +99,9 @@
// if the incoming queue was not empty.
const bool always_schedule_work_;
+ // False until StartScheduling() is called.
+ bool is_ready_for_scheduling_;
+
DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);
};
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index eb0f968..4222c77 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -100,6 +100,10 @@
}
#endif // !defined(OS_NACL_SFI)
+scoped_ptr<MessagePump> ReturnPump(scoped_ptr<MessagePump> pump) {
+ return pump;
+}
+
} // namespace
//------------------------------------------------------------------------------
@@ -116,41 +120,19 @@
//------------------------------------------------------------------------------
MessageLoop::MessageLoop(Type type)
- : type_(type),
-#if defined(OS_WIN)
- pending_high_res_tasks_(0),
- in_high_res_mode_(false),
-#endif
- nestable_tasks_allowed_(true),
-#if defined(OS_WIN)
- os_modal_loop_(false),
-#endif // OS_WIN
- message_histogram_(NULL),
- run_loop_(NULL) {
- Init();
-
- pump_ = CreateMessagePumpForType(type).Pass();
+ : MessageLoop(type, MessagePumpFactoryCallback()) {
+ BindToCurrentThread();
}
MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
- : pump_(pump.Pass()),
- type_(TYPE_CUSTOM),
-#if defined(OS_WIN)
- pending_high_res_tasks_(0),
- in_high_res_mode_(false),
-#endif
- nestable_tasks_allowed_(true),
-#if defined(OS_WIN)
- os_modal_loop_(false),
-#endif // OS_WIN
- message_histogram_(NULL),
- run_loop_(NULL) {
- DCHECK(pump_.get());
- Init();
+ : MessageLoop(TYPE_CUSTOM, Bind(&ReturnPump, Passed(&pump))) {
+ BindToCurrentThread();
}
MessageLoop::~MessageLoop() {
- DCHECK_EQ(this, current());
+ // current() could be NULL if this message loop is destructed before it is
+ // bound to a thread.
+ DCHECK(current() == this || !current());
// iOS just attaches to the loop, it doesn't Run it.
// TODO(stuartmorgan): Consider wiring up a Detach().
@@ -299,11 +281,13 @@
}
void MessageLoop::Run() {
+ DCHECK(pump_);
RunLoop run_loop;
run_loop.Run();
}
void MessageLoop::RunUntilIdle() {
+ DCHECK(pump_);
RunLoop run_loop;
run_loop.RunUntilIdle();
}
@@ -383,13 +367,43 @@
//------------------------------------------------------------------------------
-void MessageLoop::Init() {
+scoped_ptr<MessageLoop> MessageLoop::CreateUnbound(
+ Type type, MessagePumpFactoryCallback pump_factory) {
+ return make_scoped_ptr(new MessageLoop(type, pump_factory));
+}
+
+MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)
+ : type_(type),
+#if defined(OS_WIN)
+ pending_high_res_tasks_(0),
+ in_high_res_mode_(false),
+#endif
+ nestable_tasks_allowed_(true),
+#if defined(OS_WIN)
+ os_modal_loop_(false),
+#endif // OS_WIN
+ pump_factory_(pump_factory),
+ message_histogram_(NULL),
+ run_loop_(NULL),
+ incoming_task_queue_(new internal::IncomingTaskQueue(this)),
+ message_loop_proxy_(
+ new internal::MessageLoopProxyImpl(incoming_task_queue_)) {
+ // If type is TYPE_CUSTOM non-null pump_factory must be given.
+ DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null());
+}
+
+void MessageLoop::BindToCurrentThread() {
+ DCHECK(!pump_);
+ if (!pump_factory_.is_null())
+ pump_ = pump_factory_.Run();
+ else
+ pump_ = CreateMessagePumpForType(type_);
+
DCHECK(!current()) << "should only have one message loop per thread";
lazy_tls_ptr.Pointer()->Set(this);
- incoming_task_queue_ = new internal::IncomingTaskQueue(this);
- message_loop_proxy_ =
- new internal::MessageLoopProxyImpl(incoming_task_queue_);
+ incoming_task_queue_->StartScheduling();
+ message_loop_proxy_->BindToCurrentThread();
thread_task_runner_handle_.reset(
new ThreadTaskRunnerHandle(message_loop_proxy_));
}
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index fd7596a..f2f89d0 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -114,7 +114,8 @@
explicit MessageLoop(Type type = TYPE_DEFAULT);
// Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must
// be non-NULL.
- explicit MessageLoop(scoped_ptr<base::MessagePump> pump);
+ explicit MessageLoop(scoped_ptr<MessagePump> pump);
+
~MessageLoop() override;
// Returns the MessageLoop object for the current thread, or null if none.
@@ -394,10 +395,6 @@
// Returns true if the message loop is "idle". Provided for testing.
bool IsIdleForTesting();
- // Wakes up the message pump. Can be called on any thread. The caller is
- // responsible for synchronizing ScheduleWork() calls.
- void ScheduleWork();
-
// Returns the TaskAnnotator which is used to add debug information to posted
// tasks.
debug::TaskAnnotator* task_annotator() { return &task_annotator_; }
@@ -411,9 +408,33 @@
private:
friend class RunLoop;
+ friend class internal::IncomingTaskQueue;
+ friend class ScheduleWorkTest;
+ friend class Thread;
- // Configures various members for the two constructors.
- void Init();
+ using MessagePumpFactoryCallback = Callback<scoped_ptr<MessagePump>()>;
+
+ // Creates a MessageLoop without binding to a thread.
+ // If |type| is TYPE_CUSTOM non-null |pump_factory| must be also given
+ // to create a message pump for this message loop. Otherwise a default
+ // message pump for the |type| is created.
+ //
+ // It is valid to call this to create a new message loop on one thread,
+ // and then pass it to the thread where the message loop actually runs.
+ // The message loop's BindToCurrentThread() method must be called on the
+ // thread the message loop runs on, before calling Run().
+ // Before BindToCurrentThread() is called only Post*Task() functions can
+ // be called on the message loop.
+ scoped_ptr<MessageLoop> CreateUnbound(
+ Type type,
+ MessagePumpFactoryCallback pump_factory);
+
+ // Common private constructor. Other constructors delegate the initialization
+ // to this constructor.
+ MessageLoop(Type type, MessagePumpFactoryCallback pump_factory);
+
+ // Configure various members and bind this message loop to the current thread.
+ void BindToCurrentThread();
// Invokes the actual run loop using the message pump.
void RunHandler();
@@ -437,6 +458,10 @@
// empty.
void ReloadWorkQueue();
+ // Wakes up the message pump. Can be called on any thread. The caller is
+ // responsible for synchronizing ScheduleWork() calls.
+ void ScheduleWork();
+
// Start recording histogram info about events and action IF it was enabled
// and IF the statistics recorder can accept a registration of our histogram.
void StartHistogrammer();
@@ -490,6 +515,10 @@
bool os_modal_loop_;
#endif
+ // pump_factory_.Run() is called to create a message pump for this loop
+ // if type_ is TYPE_CUSTOM and pump_ is null.
+ MessagePumpFactoryCallback pump_factory_;
+
std::string thread_name_;
// A profiling histogram showing the counts of various messages and events.
HistogramBase* message_histogram_;
diff --git a/base/message_loop/message_loop_proxy.h b/base/message_loop/message_loop_proxy.h
index 88eeac4..d5ecc04 100644
--- a/base/message_loop/message_loop_proxy.h
+++ b/base/message_loop/message_loop_proxy.h
@@ -10,6 +10,18 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
+// MessageLoopProxy is deprecated. Code should prefer to depend on TaskRunner
+// (or the various specializations) for passing task runners around, and should
+// use ThreadTaskRunnerHandle::Get() to get the thread's associated task runner.
+//
+// See http://crbug.com/391045 for more details.
+// Example for these changes:
+//
+// base::MessageLoopProxy::current() -> base::ThreadTaskRunnerHandle::Get()
+// scoped_refptr<base::MessageLoopProxy> ->
+// scoped_refptr<base::SingleThreadTaskRunner>
+// base::MessageLoopProxy -> base::SingleThreadTaskRunner
+
namespace base {
// This class provides a thread-safe refcounted interface to the Post* methods
diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_proxy_impl.cc
index b7abca3..0da21a0 100644
--- a/base/message_loop/message_loop_proxy_impl.cc
+++ b/base/message_loop/message_loop_proxy_impl.cc
@@ -15,7 +15,12 @@
MessageLoopProxyImpl::MessageLoopProxyImpl(
scoped_refptr<IncomingTaskQueue> incoming_queue)
: incoming_queue_(incoming_queue),
- valid_thread_id_(PlatformThread::CurrentId()) {
+ valid_thread_id_(kInvalidThreadId) {
+}
+
+void MessageLoopProxyImpl::BindToCurrentThread() {
+ DCHECK_EQ(kInvalidThreadId, valid_thread_id_);
+ valid_thread_id_ = PlatformThread::CurrentId();
}
bool MessageLoopProxyImpl::PostDelayedTask(
diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_proxy_impl.h
index 0fe629f..c477320 100644
--- a/base/message_loop/message_loop_proxy_impl.h
+++ b/base/message_loop/message_loop_proxy_impl.h
@@ -24,6 +24,9 @@
explicit MessageLoopProxyImpl(
scoped_refptr<IncomingTaskQueue> incoming_queue);
+ // Initialize this message loop proxy on the current thread.
+ void BindToCurrentThread();
+
// MessageLoopProxy implementation
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
index b3e5604..0bf3d0c 100644
--- a/base/message_loop/message_pump_perftest.cc
+++ b/base/message_loop/message_pump_perftest.cc
@@ -20,7 +20,6 @@
#endif
namespace base {
-namespace {
class ScheduleWorkTest : public testing::Test {
public:
@@ -224,9 +223,6 @@
}
#endif
-static void DoNothing() {
-}
-
class FakeMessagePump : public MessagePump {
public:
FakeMessagePump() {}
@@ -289,5 +285,4 @@
Run(1000, 100);
}
-} // namespace
} // namespace base
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 23c28d4..39ecc30 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -31,7 +31,6 @@
g_statistics_recorder_.Get();
}
-
// static
bool StatisticsRecorder::IsActive() {
if (lock_ == NULL)
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index 3bef622..b523057 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -88,6 +88,7 @@
friend class HistogramBaseTest;
friend class HistogramSnapshotManagerTest;
friend class HistogramTest;
+ friend class JsonPrefStoreTest;
friend class SparseHistogramTest;
friend class StatisticsRecorderTest;
FRIEND_TEST_ALL_PREFIXES(HistogramDeltaSerializationTest,
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index 5205a5a..e0ce0da 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -14,9 +14,10 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
///////////////////////////////////////////////////////////////////////////////
@@ -177,7 +178,7 @@
base::AutoLock lock(list_lock_);
for (const auto& entry : observer_lists_) {
ObserverListContext* context = entry.second;
- context->loop->PostTask(
+ context->task_runner->PostTask(
from_here,
base::Bind(
&ObserverListThreadSafe<ObserverType>::template NotifyWrapper<
@@ -192,11 +193,9 @@
struct ObserverListContext {
explicit ObserverListContext(NotificationType type)
- : loop(base::MessageLoopProxy::current()),
- list(type) {
- }
+ : task_runner(base::ThreadTaskRunnerHandle::Get()), list(type) {}
- scoped_refptr<base::MessageLoopProxy> loop;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner;
ObserverList<ObserverType> list;
private:
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
index ea916b1..2e51e45 100644
--- a/base/observer_list_unittest.cc
+++ b/base/observer_list_unittest.cc
@@ -8,9 +8,10 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/location.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -107,7 +108,7 @@
void ThreadMain() override {
loop_ = new MessageLoop(); // Fire up a message loop.
- loop_->PostTask(
+ loop_->task_runner()->PostTask(
FROM_HERE,
base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
loop_->Run();
@@ -137,13 +138,14 @@
list_->Notify(FROM_HERE, &Foo::Observe, 10);
}
- loop_->PostTask(
+ loop_->task_runner()->PostTask(
FROM_HERE,
base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
}
void Quit() {
- loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+ loop_->task_runner()->PostTask(FROM_HERE,
+ MessageLoop::QuitWhenIdleClosure());
}
void Observe(int x) override {
diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc
index 60b2bb8..c05141c 100644
--- a/base/posix/unix_domain_socket_linux_unittest.cc
+++ b/base/posix/unix_domain_socket_linux_unittest.cc
@@ -10,9 +10,11 @@
#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
+#include "base/location.h"
#include "base/memory/scoped_vector.h"
#include "base/pickle.h"
#include "base/posix/unix_domain_socket_linux.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -32,11 +34,10 @@
// Have the thread send a synchronous message via the socket.
Pickle request;
- message_thread.message_loop()->PostTask(
+ message_thread.task_runner()->PostTask(
FROM_HERE,
- Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg),
- fds[1], static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL),
- request));
+ Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg), fds[1],
+ static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
// Receive the message.
ScopedVector<base::ScopedFD> message_fds;
@@ -51,9 +52,8 @@
// Check that the thread didn't get blocked.
WaitableEvent event(false, false);
- message_thread.message_loop()->PostTask(
- FROM_HERE,
- Bind(&WaitableEvent::Signal, Unretained(&event)));
+ message_thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000)));
}
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
index 47cd424..416e43f 100644
--- a/base/prefs/json_pref_store.cc
+++ b/base/prefs/json_pref_store.cc
@@ -16,9 +16,11 @@
#include "base/metrics/histogram.h"
#include "base/prefs/pref_filter.h"
#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "base/time/default_clock.h"
#include "base/values.h"
// Result returned from internal read tasks.
@@ -156,7 +158,8 @@
pref_filter_(pref_filter.Pass()),
initialized_(false),
filtering_in_progress_(false),
- read_error_(PREF_READ_ERROR_NONE) {
+ read_error_(PREF_READ_ERROR_NONE),
+ write_count_histogram_(writer_.commit_interval(), path_) {
DCHECK(!path_.empty());
}
@@ -174,7 +177,8 @@
pref_filter_(pref_filter.Pass()),
initialized_(false),
filtering_in_progress_(false),
- read_error_(PREF_READ_ERROR_NONE) {
+ read_error_(PREF_READ_ERROR_NONE),
+ write_count_histogram_(writer_.commit_interval(), path_) {
DCHECK(!path_.empty());
}
@@ -394,6 +398,8 @@
bool JsonPrefStore::SerializeData(std::string* output) {
DCHECK(CalledOnValidThread());
+ write_count_histogram_.RecordWriteOccured();
+
if (pref_filter_)
pref_filter_->FilterSerializeData(prefs_.get());
@@ -435,3 +441,91 @@
return;
}
+
+// NOTE: This value should NOT be changed without renaming the histogram
+// otherwise it will create incompatible buckets.
+const int32_t
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins = 5;
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+ const base::TimeDelta& commit_interval,
+ const base::FilePath& path)
+ : WriteCountHistogram(commit_interval,
+ path,
+ scoped_ptr<base::Clock>(new base::DefaultClock)) {
+}
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+ const base::TimeDelta& commit_interval,
+ const base::FilePath& path,
+ scoped_ptr<base::Clock> clock)
+ : commit_interval_(commit_interval),
+ path_(path),
+ clock_(clock.release()),
+ report_interval_(
+ base::TimeDelta::FromMinutes(kHistogramWriteReportIntervalMins)),
+ last_report_time_(clock_->Now()),
+ writes_since_last_report_(0) {
+}
+
+JsonPrefStore::WriteCountHistogram::~WriteCountHistogram() {
+ ReportOutstandingWrites();
+}
+
+void JsonPrefStore::WriteCountHistogram::RecordWriteOccured() {
+ ReportOutstandingWrites();
+
+ ++writes_since_last_report_;
+}
+
+void JsonPrefStore::WriteCountHistogram::ReportOutstandingWrites() {
+ base::Time current_time = clock_->Now();
+ base::TimeDelta time_since_last_report = current_time - last_report_time_;
+
+ if (time_since_last_report <= report_interval_)
+ return;
+
+ // If the time since the last report exceeds the report interval, report all
+ // the writes since the last report. They must have all occurred in the same
+ // report interval.
+ base::HistogramBase* histogram = GetHistogram();
+ histogram->Add(writes_since_last_report_);
+
+ // There may be several report intervals that elapsed that don't have any
+ // writes in them. Report these too.
+ int64 total_num_intervals_elapsed =
+ (time_since_last_report / report_interval_);
+ for (int64 i = 0; i < total_num_intervals_elapsed - 1; ++i)
+ histogram->Add(0);
+
+ writes_since_last_report_ = 0;
+ last_report_time_ += total_num_intervals_elapsed * report_interval_;
+}
+
+base::HistogramBase* JsonPrefStore::WriteCountHistogram::GetHistogram() {
+ std::string spaceless_basename;
+ base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
+ &spaceless_basename);
+ std::string histogram_name =
+ "Settings.JsonDataWriteCount." + spaceless_basename;
+
+ // The min value for a histogram is 1. The max value is the maximum number of
+ // writes that can occur in the window being recorded. The number of buckets
+ // used is the max value (plus the underflow/overflow buckets).
+ int32_t min_value = 1;
+ int32_t max_value = report_interval_ / commit_interval_;
+ int32_t num_buckets = max_value + 1;
+
+ // NOTE: These values should NOT be changed without renaming the histogram
+ // otherwise it will create incompatible buckets.
+ DCHECK_EQ(30, max_value);
+ DCHECK_EQ(31, num_buckets);
+
+ // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+ // macro adapted to allow for a dynamically suffixed histogram name.
+ // Note: The factory creates and owns the histogram.
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ histogram_name, min_value, max_value, num_buckets,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ return histogram;
+}
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
index 16e431b..1badcf2 100644
--- a/base/prefs/json_pref_store.h
+++ b/base/prefs/json_pref_store.h
@@ -13,9 +13,10 @@
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/important_file_writer.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/observer_list.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/persistent_pref_store.h"
@@ -24,11 +25,17 @@
class PrefFilter;
namespace base {
+class Clock;
class DictionaryValue;
class FilePath;
+class HistogramBase;
class SequencedTaskRunner;
class SequencedWorkerPool;
class Value;
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestBasic);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps);
}
// A writable PrefStore implementation that is used for user preferences.
@@ -98,6 +105,63 @@
const base::Closure& on_next_successful_write);
private:
+ // Represents a histogram for recording the number of writes to the pref file
+ // that occur every kHistogramWriteReportIntervalInMins minutes.
+ class BASE_PREFS_EXPORT WriteCountHistogram {
+ public:
+ static const int32_t kHistogramWriteReportIntervalMins;
+
+ WriteCountHistogram(const base::TimeDelta& commit_interval,
+ const base::FilePath& path);
+ // Constructor for testing. |clock| is a test Clock that is used to retrieve
+ // the time.
+ WriteCountHistogram(const base::TimeDelta& commit_interval,
+ const base::FilePath& path,
+ scoped_ptr<base::Clock> clock);
+ ~WriteCountHistogram();
+
+ // Record that a write has occured.
+ void RecordWriteOccured();
+
+ // Reports writes (that have not yet been reported) in all of the recorded
+ // intervals that have elapsed up until current time.
+ void ReportOutstandingWrites();
+
+ base::HistogramBase* GetHistogram();
+
+ private:
+ // The minimum interval at which writes can occur.
+ const base::TimeDelta commit_interval_;
+
+ // The path to the file.
+ const base::FilePath path_;
+
+ // Clock which is used to retrieve the current time.
+ scoped_ptr<base::Clock> clock_;
+
+ // The interval at which to report write counts.
+ const base::TimeDelta report_interval_;
+
+ // The time at which the last histogram value was reported for the number
+ // of write counts.
+ base::Time last_report_time_;
+
+ // The number of writes that have occured since the last write count was
+ // reported.
+ uint32_t writes_since_last_report_;
+
+ DISALLOW_COPY_AND_ASSIGN(WriteCountHistogram);
+ };
+
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestBasic);
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestSinglePeriod);
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestMultiplePeriods);
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestPeriodWithGaps);
+
~JsonPrefStore() override;
// This method is called after the JSON file has been read. It then hands
@@ -144,6 +208,8 @@
std::set<std::string> keys_need_empty_value_;
+ WriteCountHistogram write_count_histogram_;
+
DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
};
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
index ff68836..728a57d 100644
--- a/base/prefs/json_pref_store_unittest.cc
+++ b/base/prefs/json_pref_store_unittest.cc
@@ -7,15 +7,20 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/path_service.h"
#include "base/prefs/pref_filter.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
#include "base/values.h"
@@ -27,6 +32,12 @@
const char kHomePage[] = "homepage";
+// Set the time on the given SimpleTestClock to the given time in minutes.
+void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
+ const int32_t kBaseTimeMins = 100;
+ clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
+}
+
// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
// to the |prefs| until explicitly asked to release them.
class InterceptingPrefFilter : public PrefFilter {
@@ -97,7 +108,8 @@
void TearDown() override {
// Make sure all pending tasks have been processed (e.g., deleting the
// JsonPrefStore may post write tasks).
- message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+ message_loop_.task_runner()->PostTask(FROM_HERE,
+ MessageLoop::QuitWhenIdleClosure());
message_loop_.Run();
}
@@ -107,6 +119,10 @@
base::FilePath data_dir_;
// A message loop that we can use as the file thread message loop.
MessageLoop message_loop_;
+
+ private:
+ // Ensure histograms are reset for each test.
+ StatisticsRecorder statistics_recorder_;
};
// Test fallback behavior for a nonexistent file.
@@ -114,9 +130,7 @@
base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- bogus_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
@@ -129,11 +143,9 @@
data_dir_.AppendASCII("read_alternate.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
ASSERT_FALSE(PathExists(bogus_alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- bogus_input_file,
- bogus_alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
@@ -144,10 +156,8 @@
base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
- scoped_refptr<JsonPrefStore> pref_store =
- new JsonPrefStore(invalid_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+ invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
@@ -233,9 +243,7 @@
base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
ASSERT_TRUE(PathExists(input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
EXPECT_TRUE(pref_store->IsInitializationComplete());
@@ -262,9 +270,7 @@
base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
ASSERT_TRUE(PathExists(input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
{
MockPrefStoreObserver mock_observer;
@@ -301,9 +307,7 @@
FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- pref_file,
- message_loop_.message_loop_proxy(),
- scoped_ptr<PrefFilter>());
+ pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
// Set some keys with empty values.
pref_store->SetValue("list", new base::ListValue);
@@ -314,10 +318,8 @@
MessageLoop::current()->RunUntilIdle();
// Reload.
- pref_store = new JsonPrefStore(
- pref_file,
- message_loop_.message_loop_proxy(),
- scoped_ptr<PrefFilter>());
+ pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
+ scoped_ptr<PrefFilter>());
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
ASSERT_FALSE(pref_store->ReadOnly());
@@ -335,9 +337,7 @@
FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- pref_file,
- message_loop_.message_loop_proxy(),
- scoped_ptr<PrefFilter>());
+ pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
base::DictionaryValue* dict = new base::DictionaryValue;
dict->SetString("key", "value");
@@ -355,9 +355,7 @@
base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- bogus_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
MockPrefStoreObserver mock_observer;
pref_store->AddObserver(&mock_observer);
@@ -385,10 +383,8 @@
new InterceptingPrefFilter());
InterceptingPrefFilter* raw_intercepting_pref_filter_ =
intercepting_pref_filter.get();
- scoped_refptr<JsonPrefStore> pref_store =
- new JsonPrefStore(input_file,
- message_loop_.message_loop_proxy().get(),
- intercepting_pref_filter.Pass());
+ scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+ input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
pref_store->ReadPrefs());
@@ -432,10 +428,8 @@
new InterceptingPrefFilter());
InterceptingPrefFilter* raw_intercepting_pref_filter_ =
intercepting_pref_filter.get();
- scoped_refptr<JsonPrefStore> pref_store =
- new JsonPrefStore(input_file,
- message_loop_.message_loop_proxy().get(),
- intercepting_pref_filter.Pass());
+ scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+ input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
MockPrefStoreObserver mock_observer;
pref_store->AddObserver(&mock_observer);
@@ -498,11 +492,9 @@
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
@@ -544,11 +536,9 @@
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_TRUE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_TRUE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
@@ -586,11 +576,9 @@
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_TRUE(PathExists(input_file));
ASSERT_FALSE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_TRUE(PathExists(input_file));
ASSERT_FALSE(PathExists(alternate_input_file));
@@ -628,11 +616,9 @@
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
@@ -671,4 +657,148 @@
pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
}
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ histogram.RecordWriteOccured();
+
+ SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(1, samples->GetCount(1));
+ ASSERT_EQ(1, samples->TotalCount());
+
+ ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
+ histogram.GetHistogram()->histogram_name());
+ ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // Nothing should be recorded until the report period has elapsed.
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(0, samples->TotalCount());
+
+ SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // Now the report period has elapsed.
+ samples = histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(1, samples->GetCount(3));
+ ASSERT_EQ(1, samples->TotalCount());
+
+ // The last write won't be recorded because the second count period hasn't
+ // fully elapsed.
+ SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+
+ samples = histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(1, samples->GetCount(3));
+ ASSERT_EQ(1, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // The last write won't be recorded because the second count period hasn't
+ // fully elapsed
+ SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(2, samples->GetCount(3));
+ ASSERT_EQ(1, samples->GetCount(2));
+ ASSERT_EQ(3, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ // 1 write in the first period.
+ histogram.RecordWriteOccured();
+
+ // No writes in the second and third periods.
+
+ // 2 writes in the fourth period.
+ SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // No writes in the fifth period.
+
+ // 3 writes in the sixth period.
+ SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(3, samples->GetCount(0));
+ ASSERT_EQ(1, samples->GetCount(1));
+ ASSERT_EQ(1, samples->GetCount(2));
+ ASSERT_EQ(1, samples->GetCount(3));
+ ASSERT_EQ(6, samples->TotalCount());
+}
+
} // namespace base
diff --git a/base/prefs/pref_member.cc b/base/prefs/pref_member.cc
index 8d80dd0..64c3d6a 100644
--- a/base/prefs/pref_member.cc
+++ b/base/prefs/pref_member.cc
@@ -7,11 +7,10 @@
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/prefs/pref_service.h"
+#include "base/thread_task_runner_handle.h"
#include "base/value_conversions.h"
-using base::MessageLoopProxy;
using base::SingleThreadTaskRunner;
namespace subtle {
@@ -52,12 +51,12 @@
}
void PrefMemberBase::MoveToThread(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+ scoped_refptr<SingleThreadTaskRunner> task_runner) {
VerifyValuePrefName();
// Load the value from preferences if it hasn't been loaded so far.
if (!internal())
UpdateValueFromPref(base::Closure());
- internal()->MoveToThread(task_runner);
+ internal()->MoveToThread(task_runner.Pass());
}
void PrefMemberBase::OnPreferenceChanged(PrefService* service,
@@ -91,15 +90,14 @@
}
PrefMemberBase::Internal::Internal()
- : thread_loop_(MessageLoopProxy::current()),
+ : thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
is_managed_(false),
is_user_modifiable_(false) {
}
PrefMemberBase::Internal::~Internal() { }
bool PrefMemberBase::Internal::IsOnCorrectThread() const {
- // In unit tests, there may not be a message loop.
- return thread_loop_.get() == NULL || thread_loop_->BelongsToCurrentThread();
+ return thread_task_runner_->BelongsToCurrentThread();
}
void PrefMemberBase::Internal::UpdateValue(
@@ -115,19 +113,18 @@
is_managed_ = is_managed;
is_user_modifiable_ = is_user_modifiable;
} else {
- bool may_run = thread_loop_->PostTask(
- FROM_HERE,
- base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
- value.release(), is_managed, is_user_modifiable,
- closure_runner.Release()));
+ bool may_run = thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
+ value.release(), is_managed, is_user_modifiable,
+ closure_runner.Release()));
DCHECK(may_run);
}
}
void PrefMemberBase::Internal::MoveToThread(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+ scoped_refptr<SingleThreadTaskRunner> task_runner) {
CheckOnCorrectThread();
- thread_loop_ = task_runner;
+ thread_task_runner_ = task_runner.Pass();
}
bool PrefMemberVectorStringUpdate(const base::Value& value,
diff --git a/base/prefs/pref_member.h b/base/prefs/pref_member.h
index 9b140d1..6dceb43 100644
--- a/base/prefs/pref_member.h
+++ b/base/prefs/pref_member.h
@@ -65,8 +65,7 @@
bool is_user_modifiable,
const base::Closure& callback) const;
- void MoveToThread(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+ void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// See PrefMember<> for description.
bool IsManaged() const {
@@ -92,7 +91,7 @@
bool IsOnCorrectThread() const;
- scoped_refptr<base::SingleThreadTaskRunner> thread_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
mutable bool is_managed_;
mutable bool is_user_modifiable_;
@@ -113,8 +112,7 @@
// See PrefMember<> for description.
void Destroy();
- void MoveToThread(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+ void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// PrefObserver
void OnPreferenceChanged(PrefService* service,
@@ -201,8 +199,7 @@
// via PostTask.
// This method should only be used from the thread the PrefMember is currently
// on, which is the UI thread by default.
- void MoveToThread(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+ void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
subtle::PrefMemberBase::MoveToThread(task_runner);
}
diff --git a/base/prefs/pref_member_unittest.cc b/base/prefs/pref_member_unittest.cc
index 435122b..a776e2c 100644
--- a/base/prefs/pref_member_unittest.cc
+++ b/base/prefs/pref_member_unittest.cc
@@ -5,9 +5,10 @@
#include "base/prefs/pref_member.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/testing_pref_service.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +38,7 @@
void Init(const std::string& pref_name, PrefService* prefs) {
pref_.Init(pref_name, prefs);
- pref_.MoveToThread(pref_thread_.message_loop_proxy());
+ pref_.MoveToThread(pref_thread_.task_runner());
}
void Destroy() {
@@ -46,10 +47,9 @@
void FetchValue() {
base::WaitableEvent event(true, false);
- ASSERT_TRUE(
- pref_thread_.message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
+ ASSERT_TRUE(pref_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
event.Wait();
}
@@ -100,7 +100,11 @@
} // anonymous namespace
-TEST(PrefMemberTest, BasicGetAndSet) {
+class PrefMemberTest : public testing::Test {
+ base::MessageLoop message_loop_;
+};
+
+TEST_F(PrefMemberTest, BasicGetAndSet) {
TestingPrefServiceSimple prefs;
RegisterTestPrefs(prefs.registry());
@@ -227,7 +231,7 @@
EXPECT_EQ(expected_vector, *string_list);
}
-TEST(PrefMemberTest, InvalidList) {
+TEST_F(PrefMemberTest, InvalidList) {
// Set the vector to an initial good value.
std::vector<std::string> expected_vector;
expected_vector.push_back("foo");
@@ -245,7 +249,7 @@
EXPECT_EQ(expected_vector, vector);
}
-TEST(PrefMemberTest, TwoPrefs) {
+TEST_F(PrefMemberTest, TwoPrefs) {
// Make sure two DoublePrefMembers stay in sync.
TestingPrefServiceSimple prefs;
RegisterTestPrefs(prefs.registry());
@@ -266,7 +270,7 @@
EXPECT_EQ(4.2, *pref2);
}
-TEST(PrefMemberTest, Observer) {
+TEST_F(PrefMemberTest, Observer) {
TestingPrefServiceSimple prefs;
RegisterTestPrefs(prefs.registry());
@@ -293,12 +297,12 @@
EXPECT_EQ("hello", prefs.GetString(kStringPref));
}
-TEST(PrefMemberTest, NoInit) {
+TEST_F(PrefMemberTest, NoInit) {
// Make sure not calling Init on a PrefMember doesn't cause problems.
IntegerPrefMember pref;
}
-TEST(PrefMemberTest, MoveToThread) {
+TEST_F(PrefMemberTest, MoveToThread) {
TestingPrefServiceSimple prefs;
scoped_refptr<GetPrefValueHelper> helper(new GetPrefValueHelper());
RegisterTestPrefs(prefs.registry());
diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc
index 5afb5ea..3ccdae7 100644
--- a/base/prefs/pref_service.cc
+++ b/base/prefs/pref_service.cc
@@ -8,16 +8,18 @@
#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/prefs/default_pref_store.h"
#include "base/prefs/pref_notifier_impl.h"
#include "base/prefs/pref_registry.h"
#include "base/prefs/pref_value_store.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
#include "base/value_conversions.h"
#include "build/build_config.h"
@@ -79,10 +81,9 @@
read_error_callback_.Run(user_pref_store_->ReadPrefs());
} else {
// Guarantee that initialization happens after this function returned.
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&PersistentPrefStore::ReadPrefsAsync,
- user_pref_store_.get(),
+ base::Bind(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_.get(),
new ReadErrorHandler(read_error_callback_)));
}
}
diff --git a/base/prefs/pref_service_factory.cc b/base/prefs/pref_service_factory.cc
index d644cb1..8caf073 100644
--- a/base/prefs/pref_service_factory.cc
+++ b/base/prefs/pref_service_factory.cc
@@ -10,8 +10,8 @@
#include "base/prefs/pref_filter.h"
#include "base/prefs/pref_notifier_impl.h"
#include "base/prefs/pref_service.h"
-
#include "base/prefs/pref_value_store.h"
+#include "base/sequenced_task_runner.h"
namespace base {
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc
index ed7d7f4..d2e9ec5 100644
--- a/base/process/internal_linux.cc
+++ b/base/process/internal_linux.cc
@@ -106,12 +106,10 @@
typedef std::map<std::string, std::string> ProcStatMap;
void ParseProcStat(const std::string& contents, ProcStatMap* output) {
- typedef std::pair<std::string, std::string> StringPair;
- std::vector<StringPair> key_value_pairs;
+ base::StringPairs key_value_pairs;
SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
for (size_t i = 0; i < key_value_pairs.size(); ++i) {
- const StringPair& key_value_pair = key_value_pairs[i];
- output->insert(key_value_pair);
+ output->insert(key_value_pairs[i]);
}
}
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
index 4f8bc2d..f06a8c6 100644
--- a/base/profiler/scoped_profile.cc
+++ b/base/profiler/scoped_profile.cc
@@ -20,7 +20,6 @@
if (!birth_)
return;
- ThreadData::PrepareForStartOfRun(birth_);
stopwatch_.Start();
}
diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc
index 3fa9383..4806a90 100644
--- a/base/profiler/tracked_time_unittest.cc
+++ b/base/profiler/tracked_time_unittest.cc
@@ -78,8 +78,7 @@
}
TEST(TrackedTimeTest, TrackedTimerEnabled) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE))
+ if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE))
return;
// Make sure that when we enable tracking, we get a real timer result.
diff --git a/base/scoped_observer.h b/base/scoped_observer.h
index 5b0d533..422701b 100644
--- a/base/scoped_observer.h
+++ b/base/scoped_observer.h
@@ -48,6 +48,8 @@
sources_.end();
}
+ bool IsObservingSources() const { return !sources_.empty(); }
+
private:
Observer* observer_;
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc
index 9aae82c..0aa0f9c 100644
--- a/base/sequence_checker_unittest.cc
+++ b/base/sequence_checker_unittest.cc
@@ -9,8 +9,8 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -84,10 +84,9 @@
void PostDoStuffToOtherThread(
SequenceCheckedObject* sequence_checked_object) {
- other_thread()->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&SequenceCheckedObject::DoStuff,
- base::Unretained(sequence_checked_object)));
+ other_thread()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&SequenceCheckedObject::DoStuff,
+ base::Unretained(sequence_checked_object)));
}
void PostDeleteToOtherThread(
diff --git a/base/single_thread_task_runner.h b/base/single_thread_task_runner.h
index b5311db..6e93193 100644
--- a/base/single_thread_task_runner.h
+++ b/base/single_thread_task_runner.h
@@ -16,7 +16,8 @@
// there is a specific need to run tasks on only a single thread.
//
// SingleThreadTaskRunner implementations might:
-// - Post tasks to an existing thread's MessageLoop (see MessageLoopProxy).
+// - Post tasks to an existing thread's MessageLoop (see
+// MessageLoop::task_runner()).
// - Create their own worker thread and MessageLoop to post tasks to.
// - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
// be processed. This allows TaskRunner-oriented code run on threads
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index e084cb5..6f6d6e2 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -454,8 +454,6 @@
return DoLowerCaseEqualsASCII(a_begin, a_end, b);
}
-// TODO(port): Resolve wchar_t/iterator issues that require OS_ANDROID here.
-#if !defined(OS_ANDROID)
bool LowerCaseEqualsASCII(const char* a_begin,
const char* a_end,
const char* b) {
@@ -468,8 +466,6 @@
return DoLowerCaseEqualsASCII(a_begin, a_end, b);
}
-#endif // !defined(OS_ANDROID)
-
bool EqualsASCII(const string16& a, const base::StringPiece& b) {
if (a.length() != b.length())
return false;
diff --git a/base/synchronization/cancellation_flag_unittest.cc b/base/synchronization/cancellation_flag_unittest.cc
index 02b08b6..13c74bc 100644
--- a/base/synchronization/cancellation_flag_unittest.cc
+++ b/base/synchronization/cancellation_flag_unittest.cc
@@ -7,8 +7,9 @@
#include "base/synchronization/cancellation_flag.h"
#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/spin_wait.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
@@ -56,7 +57,7 @@
ASSERT_TRUE(t.IsRunning());
CancellationFlag flag;
- t.message_loop()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
+ t.task_runner()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
}
} // namespace
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc
index 5d7a0ab..e63a723 100644
--- a/base/synchronization/condition_variable_unittest.cc
+++ b/base/synchronization/condition_variable_unittest.cc
@@ -9,8 +9,10 @@
#include <vector>
#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/spin_wait.h"
@@ -220,7 +222,7 @@
Thread thread("Helper");
thread.Start();
- thread.message_loop()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
+ thread.task_runner()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
TimeTicks start = TimeTicks::Now();
const TimeDelta kWaitTime = TimeDelta::FromMilliseconds(300);
diff --git a/base/synchronization/waitable_event_watcher_posix.cc b/base/synchronization/waitable_event_watcher_posix.cc
index 6fc337c..ad66a4c 100644
--- a/base/synchronization/waitable_event_watcher_posix.cc
+++ b/base/synchronization/waitable_event_watcher_posix.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
@@ -68,7 +68,7 @@
bool Fire(WaitableEvent* event) override {
// Post the callback if we haven't been cancelled.
if (!flag_->value()) {
- message_loop_->PostTask(FROM_HERE, callback_);
+ message_loop_->task_runner()->PostTask(FROM_HERE, callback_);
}
// We are removed from the wait-list by the WaitableEvent itself. It only
@@ -158,7 +158,7 @@
// No hairpinning - we can't call the delegate directly here. We have to
// enqueue a task on the MessageLoop as normal.
- current_ml->PostTask(FROM_HERE, internal_callback_);
+ current_ml->task_runner()->PostTask(FROM_HERE, internal_callback_);
return true;
}
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
index ef5f1fe..9915055 100644
--- a/base/sys_info_chromeos.cc
+++ b/base/sys_info_chromeos.cc
@@ -109,7 +109,7 @@
// Parse and cache lsb_release key pairs. There should only be a handful
// of entries so the overhead for this will be small, and it can be
// useful for debugging.
- std::vector<std::pair<std::string, std::string> > pairs;
+ base::StringPairs pairs;
SplitStringIntoKeyValuePairs(lsb_release, '=', '\n', &pairs);
for (size_t i = 0; i < pairs.size(); ++i) {
std::string key, value;
diff --git a/base/task/cancelable_task_tracker.cc b/base/task/cancelable_task_tracker.cc
index b6e4b6a..a2e4799 100644
--- a/base/task/cancelable_task_tracker.cc
+++ b/base/task/cancelable_task_tracker.cc
@@ -11,9 +11,10 @@
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/cancellation_flag.h"
#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
using base::Bind;
using base::CancellationFlag;
@@ -85,7 +86,7 @@
DCHECK(thread_checker_.CalledOnValidThread());
// We need a MessageLoop to run reply.
- DCHECK(base::MessageLoopProxy::current().get());
+ DCHECK(base::ThreadTaskRunnerHandle::IsSet());
// Owned by reply callback below.
CancellationFlag* flag = new CancellationFlag();
@@ -113,7 +114,7 @@
CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
IsCanceledCallback* is_canceled_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(base::MessageLoopProxy::current().get());
+ DCHECK(base::ThreadTaskRunnerHandle::IsSet());
TaskId id = next_id_;
next_id_++; // int64 is big enough that we ignore the potential overflow.
@@ -129,7 +130,7 @@
// Will always run |untrack_and_delete_flag| on current MessageLoop.
base::ScopedClosureRunner* untrack_and_delete_flag_runner =
new base::ScopedClosureRunner(Bind(&RunOrPostToTaskRunner,
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
untrack_and_delete_flag));
*is_canceled_cb =
diff --git a/base/task/cancelable_task_tracker_unittest.cc b/base/task/cancelable_task_tracker_unittest.cc
index 8b2b86a..ff9e40b 100644
--- a/base/task/cancelable_task_tracker_unittest.cc
+++ b/base/task/cancelable_task_tracker_unittest.cc
@@ -13,8 +13,8 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -84,15 +84,13 @@
Thread worker_thread("worker thread");
ASSERT_TRUE(worker_thread.Start());
- ignore_result(task_tracker_.PostTask(worker_thread.message_loop_proxy().get(),
+ ignore_result(task_tracker_.PostTask(worker_thread.task_runner().get(),
FROM_HERE,
MakeExpectedRunClosure(FROM_HERE)));
- ignore_result(
- task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
- FROM_HERE,
- MakeExpectedRunClosure(FROM_HERE),
- MakeExpectedRunClosure(FROM_HERE)));
+ ignore_result(task_tracker_.PostTaskAndReply(
+ worker_thread.task_runner().get(), FROM_HERE,
+ MakeExpectedRunClosure(FROM_HERE), MakeExpectedRunClosure(FROM_HERE)));
CancelableTaskTracker::IsCanceledCallback is_canceled;
ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
@@ -166,11 +164,9 @@
Thread worker_thread("worker thread");
ASSERT_TRUE(worker_thread.Start());
- CancelableTaskTracker::TaskId task_id =
- task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
- FROM_HERE,
- Bind(&DoNothing),
- MakeExpectedNotRunClosure(FROM_HERE));
+ CancelableTaskTracker::TaskId task_id = task_tracker_.PostTaskAndReply(
+ worker_thread.task_runner().get(), FROM_HERE, Bind(&DoNothing),
+ MakeExpectedNotRunClosure(FROM_HERE));
EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
task_tracker_.TryCancel(task_id);
@@ -196,14 +192,14 @@
Thread other_thread("other thread");
ASSERT_TRUE(other_thread.Start());
- other_thread.message_loop_proxy()->PostTask(
+ other_thread.task_runner()->PostTask(
FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, false));
other_thread.Stop();
task_tracker_.TryCancel(task_id);
ASSERT_TRUE(other_thread.Start());
- other_thread.message_loop_proxy()->PostTask(
+ other_thread.task_runner()->PostTask(
FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, true));
other_thread.Stop();
}
@@ -378,11 +374,9 @@
Thread bad_thread("bad thread");
ASSERT_TRUE(bad_thread.Start());
- bad_thread.message_loop_proxy()->PostTask(
- FROM_HERE,
- Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
- Unretained(&task_tracker_),
- Bind(&PostDoNothingTask)));
+ bad_thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+ Unretained(&task_tracker_), Bind(&PostDoNothingTask)));
}
void TryCancel(CancelableTaskTracker::TaskId task_id,
@@ -401,11 +395,9 @@
test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
- bad_thread.message_loop_proxy()->PostTask(
- FROM_HERE,
- Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
- Unretained(&task_tracker_),
- Bind(&TryCancel, task_id)));
+ bad_thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+ Unretained(&task_tracker_), Bind(&TryCancel, task_id)));
test_task_runner->RunUntilIdle();
}
@@ -421,10 +413,9 @@
test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
- bad_thread.message_loop_proxy()->PostTask(
+ bad_thread.task_runner()->PostTask(
FROM_HERE,
- Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
- Unretained(&task_tracker_),
+ Bind(&MaybeRunDeadlyTaskTrackerMemberFunction, Unretained(&task_tracker_),
Bind(&CancelableTaskTracker::TryCancelAll)));
test_task_runner->RunUntilIdle();
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
index 481f09e..8245cfc 100644
--- a/base/task_runner_util_unittest.cc
+++ b/base/task_runner_util_unittest.cc
@@ -5,7 +5,7 @@
#include "base/task_runner_util.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -69,8 +69,7 @@
int result = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
Bind(&ReturnFourtyTwo),
Bind(&StoreValue, &result));
@@ -83,8 +82,7 @@
double result = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
Bind(&ReturnFourtyTwo),
Bind(&StoreDoubleValue, &result));
@@ -98,10 +96,8 @@
g_foo_free_count = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
- Bind(&CreateFoo),
- Bind(&ExpectFoo));
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+ Bind(&CreateFoo), Bind(&ExpectFoo));
RunLoop().RunUntilIdle();
@@ -114,10 +110,8 @@
g_foo_free_count = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
- Bind(&CreateScopedFoo),
- Bind(&ExpectScopedFoo));
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+ Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo));
RunLoop().RunUntilIdle();
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
index a104831..8a3395a 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -14,10 +14,12 @@
import junit.framework.TestResult;
import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.test.reporter.TestStatusListener;
import java.util.ArrayList;
import java.util.List;
+// TODO(jbudorick): Add support for on-device handling of timeouts.
/**
* An Instrumentation test runner that checks SDK level for tests with specific requirements.
*/
@@ -88,7 +90,7 @@
@Override
protected AndroidTestRunner getAndroidTestRunner() {
- return new AndroidTestRunner() {
+ AndroidTestRunner runner = new AndroidTestRunner() {
@Override
protected TestResult createTestResult() {
SkippingTestResult r = new SkippingTestResult();
@@ -96,6 +98,8 @@
return r;
}
};
+ runner.addTestListener(new TestStatusListener(getContext()));
+ return runner;
}
/**
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 521f69c..7f258f5 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -18,11 +18,13 @@
#include "base/format_macros.h"
#include "base/hash.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -34,6 +36,7 @@
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/test/test_switches.h"
#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -349,7 +352,7 @@
TimeDelta timeout,
int flags,
bool redirect_stdio,
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ SingleThreadTaskRunner* task_runner,
const TestLauncher::LaunchChildGTestProcessCallback& callback) {
TimeTicks start_time = TimeTicks::Now();
@@ -423,14 +426,9 @@
// Run target callback on the thread it was originating from, not on
// a worker pool thread.
- message_loop_proxy->PostTask(
- FROM_HERE,
- Bind(&RunCallback,
- callback,
- exit_code,
- TimeTicks::Now() - start_time,
- was_timeout,
- output_file_contents));
+ task_runner->PostTask(FROM_HERE, Bind(&RunCallback, callback, exit_code,
+ TimeTicks::Now() - start_time,
+ was_timeout, output_file_contents));
}
} // namespace
@@ -504,9 +502,8 @@
// Start the watchdog timer.
watchdog_timer_.Reset();
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
MessageLoop::current()->Run();
@@ -536,16 +533,10 @@
bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled();
worker_pool_owner_->pool()->PostWorkerTask(
- FROM_HERE,
- Bind(&DoLaunchChildTestProcess,
- new_command_line,
- timeout,
- flags,
- redirect_stdio,
- MessageLoopProxy::current(),
- Bind(&TestLauncher::OnLaunchTestProcessFinished,
- Unretained(this),
- callback)));
+ FROM_HERE, Bind(&DoLaunchChildTestProcess, new_command_line, timeout,
+ flags, redirect_stdio, ThreadTaskRunnerHandle::Get(),
+ Bind(&TestLauncher::OnLaunchTestProcessFinished,
+ Unretained(this), callback)));
}
void TestLauncher::OnTestFinished(const TestResult& result) {
@@ -957,9 +948,8 @@
fflush(stdout);
// No tests have actually been started, so kick off the next iteration.
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
}
}
@@ -980,7 +970,7 @@
tests_to_retry_.clear();
results_tracker_.OnTestIterationStarting();
- MessageLoop::current()->PostTask(
+ ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, Bind(&TestLauncher::RunTests, Unretained(this)));
}
@@ -1027,9 +1017,8 @@
results_tracker_.PrintSummaryOfCurrentIteration();
// Kick off the next iteration.
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
}
void TestLauncher::OnOutputTimeout() {
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index 1b3a162..ab6fa72 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -12,7 +12,9 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/format_macros.h"
+#include "base/location.h"
#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -22,6 +24,7 @@
#include "base/test/test_switches.h"
#include "base/test/test_timeouts.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_checker.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -405,13 +408,10 @@
// The temporary file's directory is also temporary.
DeleteFile(callback_state.output_file.DirName(), true);
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind(&RunUnitTestsSerially,
- callback_state.test_launcher,
- callback_state.platform_delegate,
- test_names,
- callback_state.launch_flags));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, Bind(&RunUnitTestsSerially, callback_state.test_launcher,
+ callback_state.platform_delegate, test_names,
+ callback_state.launch_flags));
}
} // namespace
@@ -576,12 +576,9 @@
size_t UnitTestLauncherDelegate::RetryTests(
TestLauncher* test_launcher,
const std::vector<std::string>& test_names) {
- MessageLoop::current()->PostTask(
+ ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- Bind(&RunUnitTestsSerially,
- test_launcher,
- platform_delegate_,
- test_names,
+ Bind(&RunUnitTestsSerially, test_launcher, platform_delegate_, test_names,
use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0));
return test_names.size();
}
diff --git a/base/test/sequenced_worker_pool_owner.cc b/base/test/sequenced_worker_pool_owner.cc
index 4486323..b0d8b7a 100644
--- a/base/test/sequenced_worker_pool_owner.cc
+++ b/base/test/sequenced_worker_pool_owner.cc
@@ -6,6 +6,7 @@
#include "base/location.h"
#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
namespace base {
@@ -50,9 +51,8 @@
}
void SequencedWorkerPoolOwner::OnDestruct() {
- constructor_message_loop_->PostTask(
- FROM_HERE,
- constructor_message_loop_->QuitWhenIdleClosure());
+ constructor_message_loop_->task_runner()->PostTask(
+ FROM_HERE, constructor_message_loop_->QuitWhenIdleClosure());
}
} // namespace base
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
index 9bcf70b..ee2b876 100644
--- a/base/test/task_runner_test_template.h
+++ b/base/test/task_runner_test_template.h
@@ -53,7 +53,9 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
@@ -195,7 +197,7 @@
i);
for (int j = 0; j < i + 1; ++j) {
task_runner->PostTask(FROM_HERE, ith_task_runner_task);
- thread.message_loop()->PostTask(FROM_HERE, ith_non_task_runner_task);
+ thread.task_runner()->PostTask(FROM_HERE, ith_non_task_runner_task);
expected_task_run_counts[i] += 2;
}
}
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index ee135e5..6c766eb 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -51,6 +51,8 @@
#include "base/test/test_support_ios.h"
#endif
+namespace base {
+
namespace {
class MaybeTestDisabler : public testing::EmptyTestEventListener {
@@ -66,35 +68,31 @@
class TestClientInitializer : public testing::EmptyTestEventListener {
public:
TestClientInitializer()
- : old_command_line_(base::CommandLine::NO_PROGRAM) {
+ : old_command_line_(CommandLine::NO_PROGRAM) {
}
void OnTestStart(const testing::TestInfo& test_info) override {
- old_command_line_ = *base::CommandLine::ForCurrentProcess();
+ old_command_line_ = *CommandLine::ForCurrentProcess();
}
void OnTestEnd(const testing::TestInfo& test_info) override {
- *base::CommandLine::ForCurrentProcess() = old_command_line_;
+ *CommandLine::ForCurrentProcess() = old_command_line_;
}
private:
- base::CommandLine old_command_line_;
+ CommandLine old_command_line_;
DISALLOW_COPY_AND_ASSIGN(TestClientInitializer);
};
} // namespace
-namespace base {
-
int RunUnitTestsUsingBaseTestSuite(int argc, char **argv) {
TestSuite test_suite(argc, argv);
- return base::LaunchUnitTests(
- argc, argv, Bind(&TestSuite::Run, Unretained(&test_suite)));
+ return LaunchUnitTests(argc, argv,
+ Bind(&TestSuite::Run, Unretained(&test_suite)));
}
-} // namespace base
-
TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) {
PreInitialize(true);
InitializeFromCommandLine(argc, argv);
@@ -116,11 +114,11 @@
TestSuite::~TestSuite() {
if (initialized_command_line_)
- base::CommandLine::Reset();
+ CommandLine::Reset();
}
void TestSuite::InitializeFromCommandLine(int argc, char** argv) {
- initialized_command_line_ = base::CommandLine::Init(argc, argv);
+ initialized_command_line_ = CommandLine::Init(argc, argv);
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
@@ -132,7 +130,7 @@
#if defined(OS_WIN)
void TestSuite::InitializeFromCommandLine(int argc, wchar_t** argv) {
// Windows CommandLine::Init ignores argv anyway.
- initialized_command_line_ = base::CommandLine::Init(argc, NULL);
+ initialized_command_line_ = CommandLine::Init(argc, NULL);
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
}
@@ -142,7 +140,7 @@
#if defined(OS_WIN)
testing::GTEST_FLAG(catch_exceptions) = false;
#endif
- base::EnableTerminationOnHeapCorruption();
+ EnableTerminationOnHeapCorruption();
#if defined(OS_LINUX) && defined(USE_AURA)
// When calling native char conversion functions (e.g wrctomb) we need to
// have the locale set. In the absence of such a call the "C" locale is the
@@ -154,7 +152,7 @@
// testing/android/native_test_wrapper.cc before main() is called.
#if !defined(OS_ANDROID)
if (create_at_exit_manager)
- at_exit_manager_.reset(new base::AtExitManager);
+ at_exit_manager_.reset(new AtExitManager);
#endif
// Don't add additional code to this function. Instead add it to
@@ -181,13 +179,13 @@
void TestSuite::AddTestLauncherResultPrinter() {
// Only add the custom printer if requested.
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kTestLauncherOutput)) {
return;
}
- FilePath output_path(base::CommandLine::ForCurrentProcess()->
- GetSwitchValuePath(switches::kTestLauncherOutput));
+ FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kTestLauncherOutput));
// Do not add the result printer if output path already exists. It's an
// indicator there is a process printing to that file, and we're likely
@@ -213,19 +211,19 @@
#endif
#if defined(OS_MACOSX)
- base::mac::ScopedNSAutoreleasePool scoped_pool;
+ mac::ScopedNSAutoreleasePool scoped_pool;
#endif
Initialize();
std::string client_func =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kTestChildProcess);
// Check to see if we are being run as a client process.
if (!client_func.empty())
return multi_process_function_list::InvokeChildProcessTest(client_func);
#if defined(OS_IOS)
- base::test_listener_ios::RegisterTestEndListener();
+ test_listener_ios::RegisterTestEndListener();
#endif
int result = RUN_ALL_TESTS();
@@ -285,9 +283,8 @@
void TestSuite::Initialize() {
#if !defined(OS_IOS)
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kWaitForDebugger)) {
- base::debug::WaitForDebugger(60, true);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kWaitForDebugger)) {
+ debug::WaitForDebugger(60, true);
}
#endif
@@ -299,9 +296,9 @@
InitAndroidTest();
#else
// Initialize logging.
- base::FilePath exe;
- PathService::Get(base::FILE_EXE, &exe);
- base::FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+ FilePath exe;
+ PathService::Get(FILE_EXE, &exe);
+ FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_ALL;
settings.log_file = log_filename.value().c_str();
@@ -312,23 +309,22 @@
logging::SetLogItems(true, true, true, true);
#endif // else defined(OS_ANDROID)
- CHECK(base::debug::EnableInProcessStackDumping());
+ CHECK(debug::EnableInProcessStackDumping());
#if defined(OS_WIN)
// Make sure we run with high resolution timer to minimize differences
// between production code and test code.
- base::Time::EnableHighResolutionTimer(true);
+ Time::EnableHighResolutionTimer(true);
#endif // defined(OS_WIN)
// In some cases, we do not want to see standard error dialogs.
- if (!base::debug::BeingDebugged() &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- "show-error-dialogs")) {
+ if (!debug::BeingDebugged() &&
+ !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
SuppressErrorDialogs();
- base::debug::SetSuppressDebugUI(true);
+ debug::SetSuppressDebugUI(true);
logging::SetLogAssertHandler(UnitTestAssertHandler);
}
- base::i18n::InitializeICU();
+ i18n::InitializeICU();
// On the Mac OS X command line, the default locale is *_POSIX. In Chromium,
// the locale is set via an OS X locale API and is never *_POSIX.
// Some tests (such as those involving word break iterator) will behave
@@ -338,11 +334,11 @@
// TODO(jshin): Should we set the locale via an OS X locale API here?
#if !defined(OS_WIN)
#if defined(OS_IOS)
- base::i18n::SetICUDefaultLocale("en_US");
+ i18n::SetICUDefaultLocale("en_US");
#else
std::string default_locale(uloc_getDefault());
if (EndsWith(default_locale, "POSIX", false))
- base::i18n::SetICUDefaultLocale("en_US");
+ i18n::SetICUDefaultLocale("en_US");
#endif
#endif
@@ -357,3 +353,5 @@
void TestSuite::Shutdown() {
}
+
+} // namespace base
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
index fa0ab6c..cf0dd3a 100644
--- a/base/test/test_suite.h
+++ b/base/test/test_suite.h
@@ -90,8 +90,4 @@
} // namespace base
-// TODO(brettw) remove this. This is a temporary hack to allow WebKit to compile
-// until we can update it to use "base::" (preventing a two-sided patch).
-using base::TestSuite;
-
#endif // BASE_TEST_TEST_SUITE_H_
diff --git a/base/test/thread_test_helper.cc b/base/test/thread_test_helper.cc
index 2bd3ba5..6a12190 100644
--- a/base/test/thread_test_helper.cc
+++ b/base/test/thread_test_helper.cc
@@ -11,9 +11,9 @@
namespace base {
ThreadTestHelper::ThreadTestHelper(
- const scoped_refptr<MessageLoopProxy>& target_thread)
+ scoped_refptr<SingleThreadTaskRunner> target_thread)
: test_result_(false),
- target_thread_(target_thread),
+ target_thread_(target_thread.Pass()),
done_event_(false, false) {
}
diff --git a/base/test/thread_test_helper.h b/base/test/thread_test_helper.h
index f6817b5..926da73 100644
--- a/base/test/thread_test_helper.h
+++ b/base/test/thread_test_helper.h
@@ -7,7 +7,7 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
namespace base {
@@ -19,7 +19,7 @@
class ThreadTestHelper : public RefCountedThreadSafe<ThreadTestHelper> {
public:
explicit ThreadTestHelper(
- const scoped_refptr<MessageLoopProxy>& target_thread);
+ scoped_refptr<SingleThreadTaskRunner> target_thread);
// True if RunTest() was successfully executed on the target thread.
bool Run() WARN_UNUSED_RESULT;
@@ -38,7 +38,7 @@
void RunInThread();
bool test_result_;
- scoped_refptr<MessageLoopProxy> target_thread_;
+ scoped_refptr<SingleThreadTaskRunner> target_thread_;
WaitableEvent done_event_;
DISALLOW_COPY_AND_ASSIGN(ThreadTestHelper);
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index 653961d..69a2b0d 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -89,6 +89,10 @@
id_(id) {
}
+ PlatformThreadId id() const {
+ return id_;
+ }
+
bool is_equal(const PlatformThreadHandle& other) const {
return handle_ == other.handle_;
}
@@ -156,9 +160,8 @@
static void Sleep(base::TimeDelta duration);
// Sets the thread name visible to debuggers/tools. This has no effect
- // otherwise. This name pointer is not copied internally. Thus, it must stay
- // valid until the thread ends.
- static void SetName(const char* name);
+ // otherwise.
+ static void SetName(const std::string& name);
// Gets the thread name, if previously set by SetName.
static const char* GetName();
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
index a31f659..11e5e2e 100644
--- a/base/threading/platform_thread_android.cc
+++ b/base/threading/platform_thread_android.cc
@@ -64,7 +64,7 @@
} // namespace internal
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
@@ -76,7 +76,7 @@
return;
// Set the name for the LWP (which gets truncated to 15 characters).
- int err = prctl(PR_SET_NAME, name);
+ int err = prctl(PR_SET_NAME, name.c_str());
if (err < 0 && errno != EPERM)
DPLOG(ERROR) << "prctl(PR_SET_NAME)";
}
diff --git a/base/threading/platform_thread_freebsd.cc b/base/threading/platform_thread_freebsd.cc
index 7ba4eed..f4fded0 100644
--- a/base/threading/platform_thread_freebsd.cc
+++ b/base/threading/platform_thread_freebsd.cc
@@ -69,7 +69,7 @@
} // namespace internal
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
@@ -80,7 +80,7 @@
// killall to stop working.
if (PlatformThread::CurrentId() == getpid())
return;
- setproctitle("%s", name);
+ setproctitle("%s", name.c_str());
#endif // !defined(OS_NACL)
}
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index b72fb5b..9f74374 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -70,7 +70,7 @@
} // namespace internal
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
@@ -87,7 +87,7 @@
// Note that glibc also has a 'pthread_setname_np' api, but it may not be
// available everywhere and it's only benefit over using prctl directly is
// that it can set the name of threads other than the current thread.
- int err = prctl(PR_SET_NAME, name);
+ int err = prctl(PR_SET_NAME, name.c_str());
// We expect EPERM failures in sandboxed processes, just ignore those.
if (err < 0 && errno != EPERM)
DPLOG(ERROR) << "prctl(PR_SET_NAME)";
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
index fd40d79..a9c347a 100644
--- a/base/threading/platform_thread_mac.mm
+++ b/base/threading/platform_thread_mac.mm
@@ -42,14 +42,14 @@
}
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
// Mac OS X does not expose the length limit of the name, so
// hardcode it.
const int kMaxNameLength = 63;
- std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+ std::string shortened_name = name.substr(0, kMaxNameLength);
// pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
// See http://crbug.com/47058
pthread_setname_np(shortened_name.c_str());
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index b9f7a56..aeaa7c7 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -108,15 +108,16 @@
// have to work running on CreateThread() threads anyway, since we run code
// on the Windows thread pool, etc. For some background on the difference:
// http://www.microsoft.com/msj/1099/win32/win321099.aspx
+ PlatformThreadId thread_id;
void* thread_handle = CreateThread(
- NULL, stack_size, ThreadFunc, params, flags, NULL);
+ NULL, stack_size, ThreadFunc, params, flags, &thread_id);
if (!thread_handle) {
delete params;
return false;
}
if (out_thread_handle)
- *out_thread_handle = PlatformThreadHandle(thread_handle);
+ *out_thread_handle = PlatformThreadHandle(thread_handle, thread_id);
else
CloseHandle(thread_handle);
return true;
@@ -154,7 +155,7 @@
}
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
// On Windows only, we don't need to tell the profiler about the "BrokerEvent"
@@ -163,7 +164,7 @@
// which would also (as a side effect) initialize the profiler in this unused
// context, including setting up thread local storage, etc. The performance
// impact is not terrible, but there is no reason to do initialize it.
- if (0 != strcmp(name, "BrokerEvent"))
+ if (name != "BrokerEvent")
tracked_objects::ThreadData::InitializeThreadContext(name);
// The debugger needs to be around to catch the name in the exception. If
@@ -173,7 +174,7 @@
if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
return;
- SetNameInternal(CurrentId(), name);
+ SetNameInternal(CurrentId(), name.c_str());
}
// static
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
index a82a4fd..f3e88ab 100644
--- a/base/threading/post_task_and_reply_impl.cc
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -25,30 +25,30 @@
class PostTaskAndReplyRelay {
public:
PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
- const Closure& task, const Closure& reply)
+ const Closure& task,
+ const Closure& reply)
: from_here_(from_here),
- origin_loop_(ThreadTaskRunnerHandle::Get()) {
+ origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
task_ = task;
reply_ = reply;
}
~PostTaskAndReplyRelay() {
- DCHECK(origin_loop_->BelongsToCurrentThread());
+ DCHECK(origin_task_runner_->BelongsToCurrentThread());
task_.Reset();
reply_.Reset();
}
void Run() {
task_.Run();
- origin_loop_->PostTask(
- from_here_,
- Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
- base::Unretained(this)));
+ origin_task_runner_->PostTask(
+ from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
+ base::Unretained(this)));
}
private:
void RunReplyAndSelfDestruct() {
- DCHECK(origin_loop_->BelongsToCurrentThread());
+ DCHECK(origin_task_runner_->BelongsToCurrentThread());
// Force |task_| to be released before |reply_| is to ensure that no one
// accidentally depends on |task_| keeping one of its arguments alive while
@@ -62,7 +62,7 @@
}
tracked_objects::Location from_here_;
- scoped_refptr<SingleThreadTaskRunner> origin_loop_;
+ scoped_refptr<SingleThreadTaskRunner> origin_task_runner_;
Closure reply_;
Closure task_;
};
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
index 076a46d..a5b9580 100644
--- a/base/threading/post_task_and_reply_impl.h
+++ b/base/threading/post_task_and_reply_impl.h
@@ -3,7 +3,7 @@
// found in the LICENSE file.
// This file contains the implementation shared by
-// MessageLoopProxy::PostTaskAndReply and WorkerPool::PostTaskAndReply.
+// TaskRunner::PostTaskAndReply and WorkerPool::PostTaskAndReply.
#ifndef BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
#define BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
@@ -21,11 +21,11 @@
// MessageLoop.
//
// If you're looking for a concrete implementation of
-// PostTaskAndReply, you probably want base::MessageLoopProxy, or you
+// PostTaskAndReply, you probably want base::SingleThreadTaskRunner, or you
// may want base::WorkerPool.
class PostTaskAndReplyImpl {
public:
- // Implementation for MessageLoopProxy::PostTaskAndReply and
+ // Implementation for TaskRunner::PostTaskAndReply and
// WorkerPool::PostTaskAndReply.
bool PostTaskAndReply(const tracked_objects::Location& from_here,
const Closure& task,
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
index 6f4a248..7bbca92 100644
--- a/base/threading/sequenced_worker_pool.cc
+++ b/base/threading/sequenced_worker_pool.cc
@@ -17,11 +17,11 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/linked_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_local.h"
@@ -777,7 +777,6 @@
this_worker->set_running_task_info(
SequenceToken(task.sequence_token_id), task.shutdown_behavior);
- tracked_objects::ThreadData::PrepareForStartOfRun(task.birth_tally);
tracked_objects::TaskStopwatch stopwatch;
stopwatch.Start();
task.task.Run();
@@ -1158,29 +1157,26 @@
return *token;
}
-SequencedWorkerPool::SequencedWorkerPool(
- size_t max_threads,
- const std::string& thread_name_prefix)
- : constructor_message_loop_(MessageLoopProxy::current()),
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+ const std::string& thread_name_prefix)
+ : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
inner_(new Inner(this, max_threads, thread_name_prefix, NULL)) {
}
-SequencedWorkerPool::SequencedWorkerPool(
- size_t max_threads,
- const std::string& thread_name_prefix,
- TestingObserver* observer)
- : constructor_message_loop_(MessageLoopProxy::current()),
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+ const std::string& thread_name_prefix,
+ TestingObserver* observer)
+ : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
inner_(new Inner(this, max_threads, thread_name_prefix, observer)) {
}
SequencedWorkerPool::~SequencedWorkerPool() {}
void SequencedWorkerPool::OnDestruct() const {
- DCHECK(constructor_message_loop_.get());
// Avoid deleting ourselves on a worker thread (which would
// deadlock).
if (RunsTasksOnCurrentThread()) {
- constructor_message_loop_->DeleteSoon(FROM_HERE, this);
+ constructor_task_runner_->DeleteSoon(FROM_HERE, this);
} else {
delete this;
}
@@ -1300,7 +1296,7 @@
}
void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) {
- DCHECK(constructor_message_loop_->BelongsToCurrentThread());
+ DCHECK(constructor_task_runner_->BelongsToCurrentThread());
inner_->Shutdown(max_new_blocking_tasks_after_shutdown);
}
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
index 0b6c5f9..ee282bc 100644
--- a/base/threading/sequenced_worker_pool.h
+++ b/base/threading/sequenced_worker_pool.h
@@ -13,6 +13,7 @@
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_runner.h"
namespace tracked_objects {
@@ -21,7 +22,7 @@
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
template <class T> class DeleteHelper;
@@ -345,7 +346,7 @@
class Inner;
class Worker;
- const scoped_refptr<MessageLoopProxy> constructor_message_loop_;
+ const scoped_refptr<SingleThreadTaskRunner> constructor_task_runner_;
// Avoid pulling in too many headers by putting (almost) everything
// into |inner_|.
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
index c12156e..05989a5 100644
--- a/base/threading/sequenced_worker_pool_unittest.cc
+++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -11,7 +11,6 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/test/sequenced_task_runner_test_template.h"
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index 028d4f4..1bc3113 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -52,7 +52,7 @@
// Construct our full name of the form "name_prefix_/TID".
name_.push_back('/');
name_.append(IntToString(tid_));
- PlatformThread::SetName(name_.c_str());
+ PlatformThread::SetName(name_);
// We've initialized our new thread, signal that we're done to Start().
event_.Signal();
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index d42ba4d..bd565c9 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
#include "base/profiler/scoped_tracker.h"
#include "base/synchronization/waitable_event.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
@@ -36,20 +37,6 @@
Thread::SetThreadWasQuitProperly(true);
}
-// Used to pass data to ThreadMain. This structure is allocated on the stack
-// from within StartWithOptions.
-struct Thread::StartupData {
- // We get away with a const reference here because of how we are allocated.
- const Thread::Options& options;
-
- // Used to synchronize thread startup.
- WaitableEvent event;
-
- explicit StartupData(const Options& opt)
- : options(opt),
- event(false, false) {}
-};
-
Thread::Options::Options()
: message_loop_type(MessageLoop::TYPE_DEFAULT),
timer_slack(TIMER_SLACK_NONE),
@@ -71,13 +58,11 @@
#if defined(OS_WIN)
com_status_(NONE),
#endif
- started_(false),
stopping_(false),
running_(false),
- startup_data_(NULL),
thread_(0),
- message_loop_(NULL),
- thread_id_(kInvalidThreadId),
+ message_loop_(nullptr),
+ message_loop_timer_slack_(TIMER_SLACK_NONE),
name_(name) {
}
@@ -103,34 +88,45 @@
SetThreadWasQuitProperly(false);
- StartupData startup_data(options);
- startup_data_ = &startup_data;
+ MessageLoop::Type type = options.message_loop_type;
+ if (!options.message_pump_factory.is_null())
+ type = MessageLoop::TYPE_CUSTOM;
+
+ message_loop_timer_slack_ = options.timer_slack;
+ message_loop_ = new MessageLoop(type, options.message_pump_factory);
+
+ start_event_.reset(new WaitableEvent(false, false));
if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
DLOG(ERROR) << "failed to create thread";
- startup_data_ = NULL;
+ delete message_loop_;
+ message_loop_ = nullptr;
+ start_event_.reset();
return false;
}
- // TODO(kinuko): Remove once crbug.com/465458 is solved.
- tracked_objects::ScopedTracker tracking_profile_wait(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "465458 base::Thread::StartWithOptions (Wait)"));
-
- // Wait for the thread to start and initialize message_loop_
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- startup_data.event.Wait();
-
- // set it to NULL so we don't keep a pointer to some object on the stack.
- startup_data_ = NULL;
- started_ = true;
-
DCHECK(message_loop_);
return true;
}
+bool Thread::StartAndWaitForTesting() {
+ bool result = Start();
+ if (!result)
+ return false;
+ WaitUntilThreadStarted();
+ return result;
+}
+
+bool Thread::WaitUntilThreadStarted() {
+ if (!start_event_)
+ return false;
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ start_event_->Wait();
+ return true;
+}
+
void Thread::Stop() {
- if (!started_)
+ if (!start_event_)
return;
StopSoon();
@@ -146,7 +142,7 @@
DCHECK(!message_loop_);
// The thread no longer needs to be joined.
- started_ = false;
+ start_event_.reset();
stopping_ = false;
}
@@ -154,25 +150,32 @@
void Thread::StopSoon() {
// We should only be called on the same thread that started us.
- // Reading thread_id_ without a lock can lead to a benign data race
- // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
- DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
+ DCHECK_NE(thread_id(), PlatformThread::CurrentId());
if (stopping_ || !message_loop_)
return;
stopping_ = true;
- message_loop_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+ task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
}
bool Thread::IsRunning() const {
+ // If the thread's already started (i.e. message_loop_ is non-null) and
+ // not yet requested to stop (i.e. stopping_ is false) we can just return
+ // true. (Note that stopping_ is touched only on the same thread that
+ // starts / started the new thread so we need no locking here.)
+ if (message_loop_ && !stopping_)
+ return true;
+ // Otherwise check the running_ flag, which is set to true by the new thread
+ // only while it is inside Run().
+ AutoLock lock(lock_);
return running_;
}
void Thread::SetPriority(ThreadPriority priority) {
// The thread must be started (and id known) for this to be
// compatible with all platforms.
- DCHECK_NE(thread_id_, kInvalidThreadId);
+ DCHECK(message_loop_ != nullptr);
PlatformThread::SetThreadPriority(thread_, priority);
}
@@ -193,60 +196,57 @@
}
void Thread::ThreadMain() {
- {
- // The message loop for this thread.
- // Allocated on the heap to centralize any leak reports at this line.
- scoped_ptr<MessageLoop> message_loop;
- if (!startup_data_->options.message_pump_factory.is_null()) {
- message_loop.reset(
- new MessageLoop(startup_data_->options.message_pump_factory.Run()));
- } else {
- message_loop.reset(
- new MessageLoop(startup_data_->options.message_loop_type));
- }
+ // Complete the initialization of our Thread object.
+ DCHECK_EQ(thread_id(), PlatformThread::CurrentId());
+ PlatformThread::SetName(name_.c_str());
+ ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
- // Complete the initialization of our Thread object.
- thread_id_ = PlatformThread::CurrentId();
- PlatformThread::SetName(name_.c_str());
- ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
- message_loop->set_thread_name(name_);
- message_loop->SetTimerSlack(startup_data_->options.timer_slack);
- message_loop_ = message_loop.get();
+ // Lazily initialize the message_loop so that it can run on this thread.
+ DCHECK(message_loop_);
+ scoped_ptr<MessageLoop> message_loop(message_loop_);
+ message_loop_->BindToCurrentThread();
+ message_loop_->set_thread_name(name_);
+ message_loop_->SetTimerSlack(message_loop_timer_slack_);
#if defined(OS_WIN)
- scoped_ptr<win::ScopedCOMInitializer> com_initializer;
- if (com_status_ != NONE) {
- com_initializer.reset((com_status_ == STA) ?
- new win::ScopedCOMInitializer() :
- new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
- }
-#endif
-
- // Let the thread do extra initialization.
- // Let's do this before signaling we are started.
- Init();
-
- running_ = true;
- startup_data_->event.Signal();
- // startup_data_ can't be touched anymore since the starting thread is now
- // unlocked.
-
- Run(message_loop_);
- running_ = false;
-
- // Let the thread do extra cleanup.
- CleanUp();
-
-#if defined(OS_WIN)
- com_initializer.reset();
-#endif
-
- // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
- DCHECK(GetThreadWasQuitProperly());
-
- // We can't receive messages anymore.
- message_loop_ = NULL;
+ scoped_ptr<win::ScopedCOMInitializer> com_initializer;
+ if (com_status_ != NONE) {
+ com_initializer.reset((com_status_ == STA) ?
+ new win::ScopedCOMInitializer() :
+ new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
}
+#endif
+
+ // Let the thread do extra initialization.
+ Init();
+
+ {
+ AutoLock lock(lock_);
+ running_ = true;
+ }
+
+ start_event_->Signal();
+
+ Run(message_loop_);
+
+ {
+ AutoLock lock(lock_);
+ running_ = false;
+ }
+
+ // Let the thread do extra cleanup.
+ CleanUp();
+
+#if defined(OS_WIN)
+ com_initializer.reset();
+#endif
+
+ // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
+ DCHECK(GetThreadWasQuitProperly());
+
+ // We can't receive messages anymore.
+ // (The message loop is destructed at the end of this block)
+ message_loop_ = NULL;
}
} // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 5010f0e..2e19b0a 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -11,13 +11,15 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/message_loop/timer_slack.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
namespace base {
class MessagePump;
+class WaitableEvent;
// A simple thread abstraction that establishes a MessageLoop on a new thread.
// The consumer uses the MessageLoop of the thread to cause code to execute on
@@ -45,7 +47,7 @@
// This is ignored if message_pump_factory.is_null() is false.
MessageLoop::Type message_loop_type;
- // Specify timer slack for thread message loop.
+ // Specifies timer slack for thread message loop.
TimerSlack timer_slack;
// Used to create the MessagePump for the MessageLoop. The callback is Run()
@@ -81,7 +83,7 @@
// init_com_with_mta(false) and then StartWithOptions() with any message loop
// type other than TYPE_UI.
void init_com_with_mta(bool use_mta) {
- DCHECK(!started_);
+ DCHECK(!start_event_);
com_status_ = use_mta ? MTA : STA;
}
#endif
@@ -103,6 +105,18 @@
// callback.
bool StartWithOptions(const Options& options);
+ // Starts the thread and wait for the thread to start and run initialization
+ // before returning. It's same as calling Start() and then
+ // WaitUntilThreadStarted().
+ // Note that using this (instead of Start() or StartWithOptions() causes
+ // jank on the calling thread, should be used only in testing code.
+ bool StartAndWaitForTesting();
+
+ // Blocks until the thread starts running. Called within StartAndWait().
+ // Note that calling this causes jank on the calling thread, must be used
+ // carefully for production code.
+ bool WaitUntilThreadStarted();
+
// Signals the thread to exit and returns once the thread has exited. After
// this method returns, the Thread object is completely reset and may be used
// as if it were newly constructed (i.e., Start may be called again).
@@ -156,7 +170,7 @@
// hold on to this even after the thread is gone; in this situation, attempts
// to PostTask() will fail.
scoped_refptr<SingleThreadTaskRunner> task_runner() const {
- return message_loop_proxy();
+ return message_loop_->task_runner();
}
// Returns the name of this thread (for display in debugger too).
@@ -166,7 +180,7 @@
PlatformThreadHandle thread_handle() { return thread_; }
// The thread ID.
- PlatformThreadId thread_id() const { return thread_id_; }
+ PlatformThreadId thread_id() const { return thread_.id(); }
// Returns true if the thread has been started, and not yet stopped.
bool IsRunning() const;
@@ -208,19 +222,13 @@
ComStatus com_status_;
#endif
- // Whether we successfully started the thread.
- bool started_;
-
// If true, we're in the middle of stopping, and shouldn't access
// |message_loop_|. It may non-NULL and invalid.
bool stopping_;
// True while inside of Run().
bool running_;
-
- // Used to pass data to ThreadMain.
- struct StartupData;
- StartupData* startup_data_;
+ mutable base::Lock lock_; // Protects running_.
// The thread's handle.
PlatformThreadHandle thread_;
@@ -229,12 +237,16 @@
// by the created thread.
MessageLoop* message_loop_;
- // Our thread's ID.
- PlatformThreadId thread_id_;
+ // Stores Options::timer_slack_ until the message loop has been bound to
+ // a thread.
+ TimerSlack message_loop_timer_slack_;
// The name of the thread. Used for debugging purposes.
std::string name_;
+ // Non-null if the thread has successfully started.
+ scoped_ptr<WaitableEvent> start_event_;
+
friend void ThreadQuitHelper();
DISALLOW_COPY_AND_ASSIGN(Thread);
diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc
index 7c85c1b..56cfa27 100644
--- a/base/threading/thread_id_name_manager.cc
+++ b/base/threading/thread_id_name_manager.cc
@@ -48,17 +48,16 @@
name_to_interned_name_[kDefaultName];
}
-void ThreadIdNameManager::SetName(PlatformThreadId id, const char* name) {
- std::string str_name(name);
-
+void ThreadIdNameManager::SetName(PlatformThreadId id,
+ const std::string& name) {
AutoLock locked(lock_);
- NameToInternedNameMap::iterator iter = name_to_interned_name_.find(str_name);
+ NameToInternedNameMap::iterator iter = name_to_interned_name_.find(name);
std::string* leaked_str = NULL;
if (iter != name_to_interned_name_.end()) {
leaked_str = iter->second;
} else {
- leaked_str = new std::string(str_name);
- name_to_interned_name_[str_name] = leaked_str;
+ leaked_str = new std::string(name);
+ name_to_interned_name_[name] = leaked_str;
}
ThreadIdToHandleMap::iterator id_to_handle_iter =
diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h
index 0ea59df..927d25f 100644
--- a/base/threading/thread_id_name_manager.h
+++ b/base/threading/thread_id_name_manager.h
@@ -27,7 +27,7 @@
void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id);
// Set the name for the given id.
- void SetName(PlatformThreadId id, const char* name);
+ void SetName(PlatformThreadId id, const std::string& name);
// Get the name for the given id.
const char* GetName(PlatformThreadId id);
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc
index b5953d5..b17c681 100644
--- a/base/threading/thread_id_name_manager_unittest.cc
+++ b/base/threading/thread_id_name_manager_unittest.cc
@@ -21,8 +21,8 @@
base::Thread thread_a(kAThread);
base::Thread thread_b(kBThread);
- thread_a.Start();
- thread_b.Start();
+ thread_a.StartAndWaitForTesting();
+ thread_b.StartAndWaitForTesting();
EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id()));
@@ -35,10 +35,10 @@
base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
base::Thread thread_a(kAThread);
- thread_a.Start();
+ thread_a.StartAndWaitForTesting();
{
base::Thread thread_b(kBThread);
- thread_b.Start();
+ thread_b.StartAndWaitForTesting();
thread_b.Stop();
}
EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
@@ -51,12 +51,12 @@
base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
base::Thread thread_a(kAThread);
- thread_a.Start();
+ thread_a.StartAndWaitForTesting();
base::PlatformThreadId a_id = thread_a.thread_id();
EXPECT_STREQ(kAThread, manager->GetName(a_id));
thread_a.Stop();
- thread_a.Start();
+ thread_a.StartAndWaitForTesting();
EXPECT_STREQ("", manager->GetName(a_id));
EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
thread_a.Stop();
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
index a08cc5b..3bc9fb4 100644
--- a/base/threading/thread_perftest.cc
+++ b/base/threading/thread_perftest.cc
@@ -5,7 +5,9 @@
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/location.h"
#include "base/memory/scoped_vector.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@@ -54,12 +56,9 @@
base::TimeTicks ThreadNow(base::Thread* thread) {
base::WaitableEvent done(false, false);
base::TimeTicks ticks;
- thread->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadPerfTest::TimeOnThread,
- base::Unretained(this),
- &ticks,
- &done));
+ thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadPerfTest::TimeOnThread,
+ base::Unretained(this), &ticks, &done));
done.Wait();
return ticks;
}
@@ -128,10 +127,9 @@
FinishMeasurement();
return;
}
- NextThread(hops)->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(
- &ThreadPerfTest::PingPong, base::Unretained(this), hops - 1));
+ NextThread(hops)->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadPerfTest::PingPong, base::Unretained(this),
+ hops - 1));
}
};
@@ -198,11 +196,9 @@
void PingPong(int hops) override {
remaining_hops_ = hops;
for (size_t i = 0; i < threads_.size(); i++) {
- threads_[i]->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&EventPerfTest::WaitAndSignalOnThread,
- base::Unretained(this),
- i));
+ threads_[i]->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&EventPerfTest::WaitAndSignalOnThread,
+ base::Unretained(this), i));
}
// Kick off the Signal ping-ponging.
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index f4d024f..e86c758 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -7,7 +7,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -144,7 +145,7 @@
EXPECT_TRUE(a.IsRunning());
bool was_invoked = false;
- a.message_loop()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
+ a.task_runner()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
// wait for the task to run (we could use a kernel event here
// instead to avoid busy waiting, but this is sufficient for
@@ -165,14 +166,12 @@
// Test that all events are dispatched before the Thread object is
// destroyed. We do this by dispatching a sleep event before the
// event that will toggle our sentinel value.
- a.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(
- static_cast<void (*)(base::TimeDelta)>(
- &base::PlatformThread::Sleep),
- base::TimeDelta::FromMilliseconds(20)));
- a.message_loop()->PostTask(FROM_HERE, base::Bind(&ToggleValue,
- &was_invoked));
+ a.task_runner()->PostTask(
+ FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>(
+ &base::PlatformThread::Sleep),
+ base::TimeDelta::FromMilliseconds(20)));
+ a.task_runner()->PostTask(FROM_HERE,
+ base::Bind(&ToggleValue, &was_invoked));
}
EXPECT_TRUE(was_invoked);
}
@@ -195,11 +194,12 @@
EXPECT_EQ("ThreadName", a.thread_name());
}
-// Make sure we can't use a thread between Start() and Init().
+// Make sure Init() is called after Start() and before
+// WaitUntilThreadInitialized() returns.
TEST_F(ThreadTest, SleepInsideInit) {
SleepInsideInitThread t;
EXPECT_FALSE(t.InitCalled());
- t.Start();
+ t.StartAndWaitForTesting();
EXPECT_TRUE(t.InitCalled());
}
@@ -221,7 +221,7 @@
// Register an observer that writes into |captured_events| once the
// thread's message loop is destroyed.
- t.message_loop()->PostTask(
+ t.task_runner()->PostTask(
FROM_HERE, base::Bind(&RegisterDestructionObserver,
base::Unretained(&loop_destruction_observer)));
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
index 769119e..c063799 100644
--- a/base/threading/watchdog.cc
+++ b/base/threading/watchdog.cc
@@ -169,7 +169,7 @@
void Watchdog::ThreadDelegate::SetThreadName() const {
std::string name = watchdog_->thread_watched_name_ + " Watchdog";
- PlatformThread::SetName(name.c_str());
+ PlatformThread::SetName(name);
DVLOG(1) << "Watchdog active: " << name;
}
diff --git a/base/threading/worker_pool.h b/base/threading/worker_pool.h
index 333b495..a52a414 100644
--- a/base/threading/worker_pool.h
+++ b/base/threading/worker_pool.h
@@ -36,7 +36,7 @@
static bool PostTask(const tracked_objects::Location& from_here,
const base::Closure& task, bool task_is_slow);
- // Just like MessageLoopProxy::PostTaskAndReply, except the destination
+ // Just like TaskRunner::PostTaskAndReply, except the destination
// for |task| is a worker thread and you can specify |task_is_slow| just
// like you can for PostTask above.
static bool PostTaskAndReply(const tracked_objects::Location& from_here,
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
index 32a5e92..349b5d7 100644
--- a/base/threading/worker_pool_posix.cc
+++ b/base/threading/worker_pool_posix.cc
@@ -77,7 +77,7 @@
const std::string name = base::StringPrintf(
"%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
// Note |name.c_str()| must remain valid for for the whole life of the thread.
- PlatformThread::SetName(name.c_str());
+ PlatformThread::SetName(name);
for (;;) {
PendingTask pending_task = pool_->WaitForTask();
@@ -87,7 +87,6 @@
"src_file", pending_task.posted_from.file_name(),
"src_func", pending_task.posted_from.function_name());
- tracked_objects::ThreadData::PrepareForStartOfRun(pending_task.birth_tally);
tracked_objects::TaskStopwatch stopwatch;
stopwatch.Start();
pending_task.task.Run();
diff --git a/base/threading/worker_pool_win.cc b/base/threading/worker_pool_win.cc
index 5469439..1b0ade5 100644
--- a/base/threading/worker_pool_win.cc
+++ b/base/threading/worker_pool_win.cc
@@ -25,8 +25,6 @@
"src_file", pending_task->posted_from.file_name(),
"src_func", pending_task->posted_from.function_name());
- tracked_objects::ThreadData::PrepareForStartOfRun(pending_task->birth_tally);
-
g_worker_pool_running_on_this_thread.Get().Set(true);
tracked_objects::TaskStopwatch stopwatch;
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 4f3819d..633ab90 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -6,13 +6,10 @@
sources = [
"java_heap_dump_provider_android.cc",
"java_heap_dump_provider_android.h",
- "memory_allocator_attributes_type_info.cc",
- "memory_allocator_attributes_type_info.h",
"memory_allocator_dump.cc",
"memory_allocator_dump.h",
"memory_dump_manager.cc",
"memory_dump_manager.h",
- "memory_dump_provider.cc",
"memory_dump_provider.h",
"memory_dump_request_args.h",
"memory_dump_session_state.cc",
@@ -88,7 +85,7 @@
source_set("trace_event_unittests") {
testonly = true
sources = [
- "memory_allocator_attributes_type_info_unittest.cc",
+ "java_heap_dump_provider_android_unittest.cc",
"memory_allocator_dump_unittest.cc",
"memory_dump_manager_unittest.cc",
"process_memory_maps_dump_provider_unittest.cc",
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
index 07cf80e..f62e356 100644
--- a/base/trace_event/etw_manifest/BUILD.gn
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -5,11 +5,8 @@
assert(is_win, "This only runs on Windows.")
# Makes the .h/.rc files from the .man file.
-action("chrome_events_win") {
- visibility = [
- "//base/trace_event/*",
- "//chrome:main_dll",
- ]
+action("chrome_events_win_generate") {
+ visibility = [ ":*" ]
script = "build/message_compiler.py"
sources = [
@@ -35,3 +32,17 @@
rebase_path("chrome_events_win.man", root_build_dir),
]
}
+
+# Compile the generated files.
+source_set("chrome_events_win") {
+ visibility = [
+ "//base/trace_event/*",
+ "//chrome:main_dll",
+ ]
+
+ sources = get_target_outputs(":chrome_events_win_generate")
+
+ deps = [
+ ":chrome_events_win_generate",
+ ]
+}
diff --git a/base/trace_event/etw_manifest/etw_manifest.gyp b/base/trace_event/etw_manifest/etw_manifest.gyp
index b0a8712..b2f0eb8 100644
--- a/base/trace_event/etw_manifest/etw_manifest.gyp
+++ b/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -6,7 +6,9 @@
{
# GN version: //base/trace_event/etw_manifest/BUILD.gn
'target_name': 'etw_manifest',
- 'type': 'static_library',
+ 'type': 'none',
+ 'toolsets': ['host', 'target'],
+ 'hard_dependency': 1,
'conditions': [
['OS=="win"', {
'sources': [
diff --git a/base/trace_event/java_heap_dump_provider_android.cc b/base/trace_event/java_heap_dump_provider_android.cc
index aa193ab..2a84b81 100644
--- a/base/trace_event/java_heap_dump_provider_android.cc
+++ b/base/trace_event/java_heap_dump_provider_android.cc
@@ -10,13 +10,6 @@
namespace base {
namespace trace_event {
-namespace {
-
-const char kDumperFriendlyName[] = "JavaHeap";
-const char kDumperName[] = "java_heap";
-
-} // namespace
-
// static
JavaHeapDumpProvider* JavaHeapDumpProvider::GetInstance() {
return Singleton<JavaHeapDumpProvider,
@@ -31,23 +24,20 @@
// Called at trace dump point time. Creates a snapshot with the memory counters
// for the current process.
-bool JavaHeapDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
- MemoryAllocatorDump* dump =
- pmd->CreateAllocatorDump(kDumperName, MemoryAllocatorDump::kRootHeap);
+bool JavaHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+ MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("java_heap");
// These numbers come from java.lang.Runtime stats.
long total_heap_size = 0;
long free_heap_size = 0;
android::JavaRuntime::GetMemoryUsage(&total_heap_size, &free_heap_size);
- dump->set_physical_size_in_bytes(total_heap_size);
- dump->set_allocated_objects_count(0);
- dump->set_allocated_objects_size_in_bytes(total_heap_size - free_heap_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, total_heap_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes,
+ total_heap_size - free_heap_size);
return true;
}
-const char* JavaHeapDumpProvider::GetFriendlyName() const {
- return kDumperFriendlyName;
-}
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/java_heap_dump_provider_android.h b/base/trace_event/java_heap_dump_provider_android.h
index 8280751..2f31047 100644
--- a/base/trace_event/java_heap_dump_provider_android.h
+++ b/base/trace_event/java_heap_dump_provider_android.h
@@ -12,13 +12,12 @@
namespace trace_event {
// Dump provider which collects process-wide memory stats.
-class JavaHeapDumpProvider : public MemoryDumpProvider {
+class BASE_EXPORT JavaHeapDumpProvider : public MemoryDumpProvider {
public:
static JavaHeapDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool DumpInto(ProcessMemoryDump* pmd) override;
- const char* GetFriendlyName() const override;
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<JavaHeapDumpProvider>;
diff --git a/base/trace_event/java_heap_dump_provider_android_unittest.cc b/base/trace_event/java_heap_dump_provider_android_unittest.cc
new file mode 100644
index 0000000..bbefba5
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 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/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(JavaHeapDumpProviderTest, JavaHeapDump) {
+ auto jhdp = JavaHeapDumpProvider::GetInstance();
+ scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+
+ jhdp->OnMemoryDump(pmd.get());
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index 7d9931c..c04b858 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -11,12 +11,6 @@
namespace base {
namespace trace_event {
-namespace {
-
-const char kDumperFriendlyName[] = "Malloc";
-
-} // namespace
-
// static
MallocDumpProvider* MallocDumpProvider::GetInstance() {
return Singleton<MallocDumpProvider,
@@ -31,12 +25,11 @@
// Called at trace dump point time. Creates a snapshot the memory counters for
// the current process.
-bool MallocDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool MallocDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
struct mallinfo info = mallinfo();
DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
- MemoryAllocatorDump* dump =
- pmd->CreateAllocatorDump("malloc", MemoryAllocatorDump::kRootHeap);
+ MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("malloc");
if (!dump)
return false;
@@ -45,20 +38,15 @@
// |arena| is 0 and the outer pages size is reported by |hblkhd|. In case of
// dlmalloc the total is given by |arena| + |hblkhd|.
// For more details see link: http://goo.gl/fMR8lF.
- dump->set_physical_size_in_bytes(info.arena + info.hblkhd);
-
- // mallinfo doesn't support any allocated object count.
- dump->set_allocated_objects_count(0);
+ dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, info.arena + info.hblkhd);
// Total allocated space is given by |uordblks|.
- dump->set_allocated_objects_size_in_bytes(info.uordblks);
+ dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, info.uordblks);
return true;
}
-const char* MallocDumpProvider::GetFriendlyName() const {
- return kDumperFriendlyName;
-}
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
index b6f6973..ec8683a 100644
--- a/base/trace_event/malloc_dump_provider.h
+++ b/base/trace_event/malloc_dump_provider.h
@@ -19,8 +19,7 @@
static MallocDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool DumpInto(ProcessMemoryDump* pmd) override;
- const char* GetFriendlyName() const override;
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<MallocDumpProvider>;
diff --git a/base/trace_event/memory_allocator_attributes_type_info.cc b/base/trace_event/memory_allocator_attributes_type_info.cc
deleted file mode 100644
index 7d1e61c..0000000
--- a/base/trace_event/memory_allocator_attributes_type_info.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2015 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/trace_event/memory_allocator_attributes_type_info.h"
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-base::LazyInstance<const std::string> kNotFound = LAZY_INSTANCE_INITIALIZER;
-
-std::string GetKey(const std::string& allocator_name,
- const std::string& attribute_name) {
- return allocator_name + "/" + attribute_name;
-}
-} // namespace
-
-MemoryAllocatorAttributesTypeInfo::MemoryAllocatorAttributesTypeInfo() {
-}
-
-MemoryAllocatorAttributesTypeInfo::~MemoryAllocatorAttributesTypeInfo() {
-}
-
-const std::string& MemoryAllocatorAttributesTypeInfo::Get(
- const std::string& allocator_name,
- const std::string& attribute_name) const {
- auto it = type_info_map_.find(GetKey(allocator_name, attribute_name));
- if (it == type_info_map_.end())
- return kNotFound.Get();
- return it->second;
-}
-
-void MemoryAllocatorAttributesTypeInfo::Set(const std::string& allocator_name,
- const std::string& attribute_name,
- const std::string& attribute_type) {
- std::string key = GetKey(allocator_name, attribute_name);
- DCHECK_EQ(0u, type_info_map_.count(key));
- type_info_map_[key] = attribute_type;
-}
-
-bool MemoryAllocatorAttributesTypeInfo::Exists(
- const std::string& allocator_name,
- const std::string& attribute_name) const {
- return type_info_map_.count(GetKey(allocator_name, attribute_name)) == 1;
-}
-
-void MemoryAllocatorAttributesTypeInfo::Update(
- const MemoryAllocatorAttributesTypeInfo& other) {
- for (auto it = other.type_info_map_.begin();
- it != other.type_info_map_.end(); ++it) {
- bool no_duplicates = type_info_map_.insert(*it).second;
- DCHECK(no_duplicates) << "Duplicated allocator attribute " << it->first;
- }
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_allocator_attributes_type_info.h b/base/trace_event/memory_allocator_attributes_type_info.h
deleted file mode 100644
index c3986ae..0000000
--- a/base/trace_event/memory_allocator_attributes_type_info.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2015 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_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
-#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
-
-#include <string>
-
-#include "base/base_export.h"
-#include "base/containers/hash_tables.h"
-
-namespace base {
-namespace trace_event {
-
-// A dictionary of "allocator_name/attribute_name" -> "attribute_type" which
-// supports merging and enforces duplicate checking.
-class BASE_EXPORT MemoryAllocatorAttributesTypeInfo {
- public:
- MemoryAllocatorAttributesTypeInfo();
- ~MemoryAllocatorAttributesTypeInfo();
-
- // Returns the attribute type, or an empty string if not found.
- const std::string& Get(const std::string& allocator_name,
- const std::string& attribute_name) const;
-
- // Refer to tools/perf/unit-info.json for the semantics of |attribute_type|.
- void Set(const std::string& allocator_name,
- const std::string& attribute_name,
- const std::string& attribute_type);
-
- // Checks whether a given {allocator_name, attribute_name} declaration exists.
- bool Exists(const std::string& allocator_name,
- const std::string& attribute_name) const;
-
- // Merges the attribute types declared in |other| into this.
- void Update(const MemoryAllocatorAttributesTypeInfo& other);
-
- private:
- // "allocator_name/attribute_name" -> attribute_type.
- hash_map<std::string, std::string> type_info_map_;
-
- DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorAttributesTypeInfo);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
diff --git a/base/trace_event/memory_allocator_attributes_type_info_unittest.cc b/base/trace_event/memory_allocator_attributes_type_info_unittest.cc
deleted file mode 100644
index 5f69fae..0000000
--- a/base/trace_event/memory_allocator_attributes_type_info_unittest.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2015 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/trace_event/memory_allocator_attributes_type_info.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-TEST(MemoryAllocatorAttributesTypeInfoTest, BasicTest) {
- MemoryAllocatorAttributesTypeInfo attrs;
- EXPECT_EQ("", attrs.Get("non_existing_alloc", "non_existing_attr"));
-
- attrs.Set("alloc", "attr", "type");
- EXPECT_TRUE(attrs.Exists("alloc", "attr"));
- EXPECT_FALSE(attrs.Exists("alloc", "foo"));
- EXPECT_FALSE(attrs.Exists("foo", "attr"));
- EXPECT_EQ("type", attrs.Get("alloc", "attr"));
-
- attrs.Set("alloc2", "attr", "type2");
- EXPECT_TRUE(attrs.Exists("alloc2", "attr"));
- EXPECT_FALSE(attrs.Exists("alloc2", "foo"));
- EXPECT_EQ("type", attrs.Get("alloc", "attr"));
- EXPECT_EQ("type2", attrs.Get("alloc2", "attr"));
-
- MemoryAllocatorAttributesTypeInfo other_attrs;
- other_attrs.Set("other_alloc", "other_attr", "other_type");
- other_attrs.Set("other_alloc", "attr", "other_type2");
- other_attrs.Set("other_alloc_2", "other_attr", "other_type");
- other_attrs.Set("other_alloc_2", "attr", "other_type3");
-
- // Check the merging logic.
- attrs.Update(other_attrs);
- EXPECT_EQ("other_type", attrs.Get("other_alloc", "other_attr"));
- EXPECT_EQ("other_type2", attrs.Get("other_alloc", "attr"));
- EXPECT_EQ("other_type", attrs.Get("other_alloc_2", "other_attr"));
- EXPECT_EQ("other_type3", attrs.Get("other_alloc_2", "attr"));
- EXPECT_EQ("type", attrs.Get("alloc", "attr"));
- EXPECT_EQ("type2", attrs.Get("alloc2", "attr"));
- EXPECT_FALSE(other_attrs.Exists("alloc", "attr"));
- EXPECT_FALSE(other_attrs.Exists("alloc2", "attr"));
-}
-
-// DEATH tests are not supported in Android / iOS.
-#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
-TEST(MemoryAllocatorAttributesTypeInfoTest, DuplicatesDeathTest) {
- MemoryAllocatorAttributesTypeInfo attrs;
- attrs.Set("alloc", "attr", "type");
- MemoryAllocatorAttributesTypeInfo conflicting_attrs;
- conflicting_attrs.Set("alloc", "attr", "type2");
- ASSERT_DEATH(attrs.Set("alloc", "attr", "other_type"), "");
- ASSERT_DEATH(attrs.Update(conflicting_attrs), "");
-}
-#endif
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
index 1d2fb3f..77c32ec 100644
--- a/base/trace_event/memory_allocator_dump.cc
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -15,114 +15,105 @@
namespace base {
namespace trace_event {
-// static
-const char MemoryAllocatorDump::kRootHeap[] = "";
-
-// static
-std::string MemoryAllocatorDump::GetAbsoluteName(
- const std::string& allocator_name,
- const std::string& heap_name) {
- return allocator_name + (heap_name == kRootHeap ? "" : "/" + heap_name);
+namespace {
+// Returns the c-string pointer from a dictionary value without performing extra
+// std::string copies. The ptr will be valid as long as the value exists.
+bool GetDictionaryValueAsCStr(const DictionaryValue* dict_value,
+ const std::string& key,
+ const char** out_cstr) {
+ const Value* value = nullptr;
+ const StringValue* str_value = nullptr;
+ if (!dict_value->GetWithoutPathExpansion(key, &value))
+ return false;
+ if (!value->GetAsString(&str_value))
+ return false;
+ *out_cstr = str_value->GetString().c_str();
+ return true;
}
+} // namespace
-MemoryAllocatorDump::MemoryAllocatorDump(const std::string& allocator_name,
- const std::string& heap_name,
+const char MemoryAllocatorDump::kNameOuterSize[] = "outer_size";
+const char MemoryAllocatorDump::kNameInnerSize[] = "inner_size";
+const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
+const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
+const char MemoryAllocatorDump::kTypeString[] = "string";
+const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
+const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
+
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
ProcessMemoryDump* process_memory_dump)
- : allocator_name_(allocator_name),
- heap_name_(heap_name),
- process_memory_dump_(process_memory_dump),
- physical_size_in_bytes_(0),
- allocated_objects_count_(0),
- allocated_objects_size_in_bytes_(0) {
- // The allocator name cannot be empty or contain slash separators.
- DCHECK(!allocator_name.empty());
- DCHECK_EQ(std::string::npos, allocator_name.find_first_of('/'));
+ : absolute_name_(absolute_name), process_memory_dump_(process_memory_dump) {
+ // The |absolute_name| cannot be empty.
+ DCHECK(!absolute_name.empty());
- // The heap_name can be empty and contain slash separator, but not
- // leading or trailing ones.
- DCHECK(heap_name.empty() ||
- (heap_name[0] != '/' && *heap_name.rbegin() != '/'));
+ // The |absolute_name| can contain slash separator, but not leading or
+ // trailing ones.
+ DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
// Dots are not allowed anywhere as the underlying base::DictionaryValue
// would treat them magically and split in sub-nodes, which is not intended.
- DCHECK_EQ(std::string::npos, allocator_name.find_first_of('.'));
- DCHECK_EQ(std::string::npos, heap_name.find_first_of('.'));
+ DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
}
MemoryAllocatorDump::~MemoryAllocatorDump() {
}
-void MemoryAllocatorDump::SetAttribute(const std::string& name, int value) {
- DCHECK(GetAttributesTypeInfo().Exists(allocator_name_, name))
- << "attribute '" << name << "' not declared."
- << "See MemoryDumpProvider.DeclareAllocatorAttribute()";
- attributes_values_.SetInteger(name, value);
+void MemoryAllocatorDump::Add(const std::string& name,
+ const char* type,
+ const char* units,
+ scoped_ptr<Value> value) {
+ scoped_ptr<DictionaryValue> attribute(new DictionaryValue());
+ DCHECK(!attributes_.HasKey(name));
+ attribute->SetStringWithoutPathExpansion("type", type);
+ attribute->SetStringWithoutPathExpansion("units", units);
+ attribute->SetWithoutPathExpansion("value", value.Pass());
+ attributes_.SetWithoutPathExpansion(name, attribute.Pass());
}
-std::string MemoryAllocatorDump::GetAbsoluteName() const {
- return GetAbsoluteName(allocator_name_, heap_name_);
+bool MemoryAllocatorDump::Get(const std::string& name,
+ const char** out_type,
+ const char** out_units,
+ const Value** out_value) const {
+ const DictionaryValue* attribute = nullptr;
+ if (!attributes_.GetDictionaryWithoutPathExpansion(name, &attribute))
+ return false;
+
+ if (!GetDictionaryValueAsCStr(attribute, "type", out_type))
+ return false;
+
+ if (!GetDictionaryValueAsCStr(attribute, "units", out_units))
+ return false;
+
+ if (!attribute->GetWithoutPathExpansion("value", out_value))
+ return false;
+
+ return true;
}
-int MemoryAllocatorDump::GetIntegerAttribute(const std::string& name) const {
- int value = -1;
- bool res = attributes_values_.GetInteger(name, &value);
- DCHECK(res) << "Attribute '" << name << "' not found";
- return value;
+void MemoryAllocatorDump::AddScalar(const std::string& name,
+ const char* units,
+ uint64 value) {
+ scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
+ Add(name, kTypeScalar, units, hex_value.Pass());
+}
+
+void MemoryAllocatorDump::AddString(const std::string& name,
+ const char* units,
+ const std::string& value) {
+ scoped_ptr<Value> str_value(new StringValue(value));
+ Add(name, kTypeString, units, str_value.Pass());
}
void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
- static const char kHexFmt[] = "%" PRIx64;
-
- value->BeginDictionary(GetAbsoluteName().c_str());
+ value->BeginDictionary(absolute_name_.c_str());
value->BeginDictionary("attrs");
- // TODO(primiano): these hard-coded types are temporary to transition to the
- // new generalized attribute format. This code will be refactored by the end
- // of May 2015.
- value->BeginDictionary("outer_size");
- value->SetString("type", "scalar");
- value->SetString("units", "bytes");
- value->SetString("value", StringPrintf(kHexFmt, physical_size_in_bytes_));
- value->EndDictionary();
-
- value->BeginDictionary("inner_size");
- value->SetString("type", "scalar");
- value->SetString("units", "bytes");
- value->SetString("value",
- StringPrintf(kHexFmt, allocated_objects_size_in_bytes_));
- value->EndDictionary();
-
- value->BeginDictionary("objects_count");
- value->SetString("type", "scalar");
- value->SetString("units", "objects");
- value->SetString("value", StringPrintf(kHexFmt, allocated_objects_count_));
- value->EndDictionary();
-
- // Copy all the extra attributes.
- for (DictionaryValue::Iterator it(attributes_values_); !it.IsAtEnd();
- it.Advance()) {
- const std::string& attr_name = it.key();
- const Value& attr_value = it.value();
- value->BeginDictionary(attr_name.c_str());
- value->SetValue("value", attr_value.DeepCopy());
-
- const std::string& attr_type =
- GetAttributesTypeInfo().Get(allocator_name_, attr_name);
- DCHECK(!attr_type.empty());
- value->SetString("type", "scalar");
- value->SetString("units", attr_type);
-
- value->EndDictionary(); // "arg_name": { "type": "...", "value": "..." }
- }
+ for (DictionaryValue::Iterator it(attributes_); !it.IsAtEnd(); it.Advance())
+ value->SetValue(it.key().c_str(), it.value().DeepCopy());
value->EndDictionary(); // "attrs": { ... }
value->EndDictionary(); // "allocator_name/heap_subheap": { ... }
}
-const MemoryAllocatorAttributesTypeInfo&
-MemoryAllocatorDump::GetAttributesTypeInfo() const {
- return process_memory_dump_->session_state()->allocators_attributes_type_info;
-}
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index 1c786ab..1bb27f9 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -8,7 +8,6 @@
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/logging.h"
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
#include "base/values.h"
namespace base {
@@ -21,58 +20,45 @@
// Data model for user-land memory allocator dumps.
class BASE_EXPORT MemoryAllocatorDump {
public:
- // Returns the absolute name for a given (|allocator_name|,|heap_name|) tuple.
- static std::string GetAbsoluteName(const std::string& allocator_name,
- const std::string& heap_name);
-
- // Use as argument for |heap_name| when the allocator has only one root heap.
- static const char kRootHeap[];
-
// MemoryAllocatorDump is owned by ProcessMemoryDump.
- MemoryAllocatorDump(const std::string& allocator_name,
- const std::string& heap_name,
+ MemoryAllocatorDump(const std::string& absolute_name,
ProcessMemoryDump* process_memory_dump);
~MemoryAllocatorDump();
- // Name of the allocator, a plain string with no separators (e.g, "malloc").
- const std::string& allocator_name() const { return allocator_name_; }
+ // Standard attribute name to model total space requested by the allocator
+ // (e.g., amount of pages requested to the system).
+ static const char kNameOuterSize[];
- // Name of the heap being dumped, either: "heap", "heap/subheap" or kRootHeap
- // if the allocator has just one root heap.
- const std::string& heap_name() const { return heap_name_; }
+ // Standard attribute name to model space for allocated objects, without
+ // taking into account allocator metadata or fragmentation.
+ static const char kNameInnerSize[];
+
+ // Standard attribute name to model the number of objects allocated.
+ static const char kNameObjectsCount[];
+
+ static const char kTypeScalar[]; // Type name for scalar attributes.
+ static const char kTypeString[]; // Type name for string attributes.
+ static const char kUnitsBytes[]; // Unit name to represent bytes.
+ static const char kUnitsObjects[]; // Unit name to represent #objects.
// Absolute name, unique within the scope of an entire ProcessMemoryDump.
- // In practice this is "allocator_name/heap/subheap".
- std::string GetAbsoluteName() const;
+ const std::string& absolute_name() const { return absolute_name_; }
- // Inner size: Bytes requested by clients of the allocator, without accounting
- // for any metadata or allocator-specific bookeeping structs.
- void set_allocated_objects_size_in_bytes(uint64 value) {
- allocated_objects_size_in_bytes_ = value;
- }
- uint64 allocated_objects_size_in_bytes() const {
- return allocated_objects_size_in_bytes_;
- }
+ // Generic attribute setter / getter.
+ void Add(const std::string& name,
+ const char* type,
+ const char* units,
+ scoped_ptr<Value> value);
+ bool Get(const std::string& name,
+ const char** out_type,
+ const char** out_units,
+ const Value** out_value) const;
- // Outer size: bytes requested to the system to handle all the allocations,
- // including any allocator-internal metadata / bookeeping structs. For
- // instance, in the case of an allocator which gets pages to the system via
- // mmap() or similar, this is the number of requested pages * 4k.
- void set_physical_size_in_bytes(uint64 value) {
- physical_size_in_bytes_ = value;
- }
- uint64 physical_size_in_bytes() const { return physical_size_in_bytes_; }
-
- // Number of objects allocated, if known, or 0 if not available.
- void set_allocated_objects_count(uint64 value) {
- allocated_objects_count_ = value;
- }
- uint64 allocated_objects_count() const { return allocated_objects_count_; }
-
- // Get/Set extra attributes. The attributes name must have been previously
- // declared through MemoryDumpProvider.DeclareAllocatorAttribute().
- void SetAttribute(const std::string& name, int value);
- int GetIntegerAttribute(const std::string& name) const;
+ // Helper setter for scalar attributes.
+ void AddScalar(const std::string& name, const char* units, uint64 value);
+ void AddString(const std::string& name,
+ const char* units,
+ const std::string& value);
// Called at trace generation time to populate the TracedValue.
void AsValueInto(TracedValue* value) const;
@@ -82,18 +68,10 @@
return process_memory_dump_;
}
- // Retrieves the map of allocator attributes types, which is shared by all
- // MemoryAllocatorDump(s) across all ProcessMemoryDump(s) per tracing session.
- const MemoryAllocatorAttributesTypeInfo& GetAttributesTypeInfo() const;
-
private:
- const std::string allocator_name_;
- const std::string heap_name_;
+ const std::string absolute_name_;
ProcessMemoryDump* const process_memory_dump_; // Not owned (PMD owns this).
- uint64 physical_size_in_bytes_;
- uint64 allocated_objects_count_;
- uint64 allocated_objects_size_in_bytes_;
- DictionaryValue attributes_values_;
+ DictionaryValue attributes_;
DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
};
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
index 110a25d..0b2cbdf 100644
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -4,6 +4,8 @@
#include "base/trace_event/memory_allocator_dump.h"
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/memory_dump_session_state.h"
#include "base/trace_event/process_memory_dump.h"
@@ -17,80 +19,115 @@
class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
public:
- FakeMemoryAllocatorDumpProvider() {
- DeclareAllocatorAttribute("foobar_allocator", "attr1", "count");
- DeclareAllocatorAttribute("foobar_allocator", "attr2", "bytes");
- }
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override {
+ MemoryAllocatorDump* root_heap =
+ pmd->CreateAllocatorDump("foobar_allocator");
- bool DumpInto(ProcessMemoryDump* pmd) override {
- MemoryAllocatorDump* root_heap = pmd->CreateAllocatorDump(
- "foobar_allocator", MemoryAllocatorDump::kRootHeap);
- root_heap->set_physical_size_in_bytes(4096);
- root_heap->set_allocated_objects_count(42);
- root_heap->set_allocated_objects_size_in_bytes(1000);
- root_heap->SetAttribute("attr1", 1234);
- root_heap->SetAttribute("attr2", 99);
+ root_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, 4096);
+ root_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, 1000);
+ root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kUnitsObjects, 42);
+ root_heap->AddScalar("attr1", "units1", 1234);
+ root_heap->AddString("attr2", "units2", "string_value");
MemoryAllocatorDump* sub_heap =
- pmd->CreateAllocatorDump("foobar_allocator", "sub_heap");
- sub_heap->set_physical_size_in_bytes(1);
- sub_heap->set_allocated_objects_count(2);
- sub_heap->set_allocated_objects_size_in_bytes(3);
+ pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
+ sub_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, 1);
+ sub_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, 2);
+ sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kUnitsObjects, 3);
- pmd->CreateAllocatorDump("foobar_allocator", "sub_heap/empty");
+ pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
// Leave the rest of sub heap deliberately uninitialized, to check that
// CreateAllocatorDump returns a properly zero-initialized object.
return true;
}
-
- const char* GetFriendlyName() const override { return "FooBar Allocator"; }
};
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+ const std::string& name,
+ const char* expected_type,
+ const char* expected_units,
+ const std::string& expected_value) {
+ const char* attr_type;
+ const char* attr_units;
+ const Value* attr_value;
+ std::string attr_str_value;
+ bool res = dump->Get(name, &attr_type, &attr_units, &attr_value);
+ EXPECT_TRUE(res);
+ if (!res)
+ return;
+ EXPECT_EQ(expected_type, std::string(attr_type));
+ EXPECT_EQ(expected_units, std::string(attr_units));
+ EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
+ EXPECT_EQ(expected_value, attr_str_value);
+}
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+ const std::string& name,
+ const char* expected_type,
+ const char* expected_units,
+ uint64 expected_value) {
+ CheckAttribute(dump, name, expected_type, expected_units,
+ StringPrintf("%" PRIx64, expected_value));
+}
} // namespace
TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
FakeMemoryAllocatorDumpProvider fmadp;
ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
- pmd.session_state()->allocators_attributes_type_info.Update(
- fmadp.allocator_attributes_type_info());
- fmadp.DumpInto(&pmd);
+ fmadp.OnMemoryDump(&pmd);
ASSERT_EQ(3u, pmd.allocator_dumps().size());
const MemoryAllocatorDump* root_heap =
- pmd.GetAllocatorDump("foobar_allocator", MemoryAllocatorDump::kRootHeap);
+ pmd.GetAllocatorDump("foobar_allocator");
ASSERT_NE(nullptr, root_heap);
- EXPECT_EQ("foobar_allocator", root_heap->allocator_name());
- EXPECT_EQ("", root_heap->heap_name());
- EXPECT_NE("", root_heap->GetAbsoluteName());
- EXPECT_EQ(4096u, root_heap->physical_size_in_bytes());
- EXPECT_EQ(42u, root_heap->allocated_objects_count());
- EXPECT_EQ(1000u, root_heap->allocated_objects_size_in_bytes());
-
- // Check the extra attributes of |root_heap|.
- EXPECT_EQ(1234, root_heap->GetIntegerAttribute("attr1"));
- EXPECT_EQ(99, root_heap->GetIntegerAttribute("attr2"));
+ EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
+ CheckAttribute(root_heap, MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 4096);
+ CheckAttribute(root_heap, MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 1000);
+ CheckAttribute(root_heap, MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsObjects, 42);
+ CheckAttribute(root_heap, "attr1", MemoryAllocatorDump::kTypeScalar, "units1",
+ 1234);
+ CheckAttribute(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
+ "string_value");
const MemoryAllocatorDump* sub_heap =
- pmd.GetAllocatorDump("foobar_allocator", "sub_heap");
+ pmd.GetAllocatorDump("foobar_allocator/sub_heap");
ASSERT_NE(nullptr, sub_heap);
- EXPECT_EQ("foobar_allocator", sub_heap->allocator_name());
- EXPECT_EQ("sub_heap", sub_heap->heap_name());
- EXPECT_NE("", sub_heap->GetAbsoluteName());
- EXPECT_EQ(1u, sub_heap->physical_size_in_bytes());
- EXPECT_EQ(2u, sub_heap->allocated_objects_count());
- EXPECT_EQ(3u, sub_heap->allocated_objects_size_in_bytes());
+ EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
+ CheckAttribute(sub_heap, MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 1);
+ CheckAttribute(sub_heap, MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 2);
+ CheckAttribute(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsObjects, 3);
const MemoryAllocatorDump* empty_sub_heap =
- pmd.GetAllocatorDump("foobar_allocator", "sub_heap/empty");
+ pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
ASSERT_NE(nullptr, empty_sub_heap);
- EXPECT_EQ("foobar_allocator", empty_sub_heap->allocator_name());
- EXPECT_EQ("sub_heap/empty", empty_sub_heap->heap_name());
- EXPECT_NE("", sub_heap->GetAbsoluteName());
- EXPECT_EQ(0u, empty_sub_heap->physical_size_in_bytes());
- EXPECT_EQ(0u, empty_sub_heap->allocated_objects_count());
- EXPECT_EQ(0u, empty_sub_heap->allocated_objects_size_in_bytes());
+ EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
+ ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameOuterSize, nullptr,
+ nullptr, nullptr));
+ ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameInnerSize, nullptr,
+ nullptr, nullptr));
+ ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameObjectsCount,
+ nullptr, nullptr, nullptr));
// Check that the AsValueInfo doesn't hit any DCHECK.
scoped_refptr<TracedValue> traced_value(new TracedValue());
@@ -102,13 +139,11 @@
TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
FakeMemoryAllocatorDumpProvider fmadp;
ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
- pmd.CreateAllocatorDump("foo_allocator", MemoryAllocatorDump::kRootHeap);
- pmd.CreateAllocatorDump("bar_allocator", "heap");
- ASSERT_DEATH(
- pmd.CreateAllocatorDump("foo_allocator", MemoryAllocatorDump::kRootHeap),
- "");
- ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator", "heap"), "");
- ASSERT_DEATH(pmd.CreateAllocatorDump("", "must_have_allocator_name"), "");
+ pmd.CreateAllocatorDump("foo_allocator");
+ pmd.CreateAllocatorDump("bar_allocator/heap");
+ ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
+ ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
+ ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
}
#endif
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 859e8e0..1e4d822 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -12,12 +12,22 @@
#include "base/trace_event/memory_dump_session_state.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#if !defined(OS_NACL)
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+#endif
#if defined(OS_LINUX) || defined(OS_ANDROID)
#include "base/trace_event/malloc_dump_provider.h"
#include "base/trace_event/process_memory_maps_dump_provider.h"
-#include "base/trace_event/process_memory_totals_dump_provider.h"
-#elif defined(OS_WIN)
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/trace_event/java_heap_dump_provider_android.h"
+#endif
+
+#if defined(OS_WIN)
#include "base/trace_event/winheap_dump_provider_win.h"
#endif
@@ -144,8 +154,7 @@
}
MemoryDumpManager::MemoryDumpManager()
- : dump_provider_currently_active_(nullptr),
- delegate_(nullptr),
+ : delegate_(nullptr),
memory_tracing_enabled_(0),
skip_core_dumpers_auto_registration_for_testing_(false) {
g_next_guid.GetNext(); // Make sure that first guid is not zero.
@@ -162,12 +171,21 @@
if (skip_core_dumpers_auto_registration_for_testing_)
return;
-#if defined(OS_LINUX) || defined(OS_ANDROID)
// Enable the core dump providers.
+#if !defined(OS_NACL)
RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
RegisterDumpProvider(MallocDumpProvider::GetInstance());
-#elif defined(OS_WIN)
+#endif
+
+#if defined(OS_ANDROID)
+ RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_WIN)
RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
#endif
}
@@ -178,30 +196,41 @@
delegate_ = delegate;
}
-void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+void MemoryDumpManager::RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+ MemoryDumpProviderInfo mdp_info(task_runner);
AutoLock lock(lock_);
- dump_providers_registered_.insert(mdp);
+ dump_providers_.insert(std::make_pair(mdp, mdp_info));
+}
+
+void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+ RegisterDumpProvider(mdp, nullptr);
}
void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
AutoLock lock(lock_);
+ auto it = dump_providers_.find(mdp);
+ if (it == dump_providers_.end())
+ return;
+
+ const MemoryDumpProviderInfo& mdp_info = it->second;
// Unregistration of a MemoryDumpProvider while tracing is ongoing is safe
// only if the MDP has specified a thread affinity (via task_runner()) AND
// the unregistration happens on the same thread (so the MDP cannot unregister
- // and DumpInto() at the same time).
+ // and OnMemoryDump() at the same time).
// Otherwise, it is not possible to guarantee that its unregistration is
// race-free. If you hit this DCHECK, your MDP has a bug.
DCHECK_IMPLIES(
subtle::NoBarrier_Load(&memory_tracing_enabled_),
- mdp->task_runner() && mdp->task_runner()->BelongsToCurrentThread())
- << "The MemoryDumpProvider " << mdp->GetFriendlyName() << " attempted to "
- << "unregister itself in a racy way. Please file a crbug.";
+ mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread())
+ << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
+ << " Please file a crbug.";
// Remove from the enabled providers list. This is to deal with the case that
// UnregisterDumpProvider is called while the trace is enabled.
- dump_providers_enabled_.erase(mdp);
- dump_providers_registered_.erase(mdp);
+ dump_providers_.erase(it);
}
void MemoryDumpManager::RequestGlobalDump(
@@ -244,25 +273,26 @@
ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
bool did_any_provider_dump = false;
- // Iterate over the active dump providers and invoke DumpInto(pmd).
+ // Iterate over the active dump providers and invoke OnMemoryDump(pmd).
// The MDM guarantees linearity (at most one MDP is active within one
// process) and thread-safety (MDM enforces the right locking when entering /
- // leaving the MDP.DumpInto() call). This is to simplify the clients' design
+ // leaving the MDP.OnMemoryDump() call). This is to simplify the clients'
+ // design
// and not let the MDPs worry about locking.
// As regards thread affinity, depending on the MDP configuration (see
- // memory_dump_provider.h), the DumpInto() invocation can happen:
+ // memory_dump_provider.h), the OnMemoryDump() invocation can happen:
// - Synchronousy on the MDM thread, when MDP.task_runner() is not set.
// - Posted on MDP.task_runner(), when MDP.task_runner() is set.
{
AutoLock lock(lock_);
- for (auto dump_provider_iter = dump_providers_enabled_.begin();
- dump_provider_iter != dump_providers_enabled_.end();) {
- // InvokeDumpProviderLocked will remove the MDP from the set if it fails.
- MemoryDumpProvider* mdp = *dump_provider_iter;
- ++dump_provider_iter;
- if (mdp->task_runner()) {
- // The DumpInto() call must be posted.
- bool did_post_async_task = mdp->task_runner()->PostTask(
+ for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
+ MemoryDumpProvider* mdp = it->first;
+ MemoryDumpProviderInfo* mdp_info = &it->second;
+ if (mdp_info->disabled)
+ continue;
+ if (mdp_info->task_runner) {
+ // The OnMemoryDump() call must be posted.
+ bool did_post_async_task = mdp_info->task_runner->PostTask(
FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
Unretained(this), Unretained(mdp), pmd_holder));
// The thread underlying the TaskRunner might have gone away.
@@ -282,27 +312,24 @@
FinalizeDumpAndAddToTrace(pmd_holder);
}
-// Invokes the MemoryDumpProvider.DumpInto(), taking care of the failsafe logic
-// which disables the dumper when failing (crbug.com/461788).
+// Invokes the MemoryDumpProvider.OnMemoryDump(), taking care of the fail-safe
+// logic which disables the dumper when failing (crbug.com/461788).
bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
ProcessMemoryDump* pmd) {
lock_.AssertAcquired();
- dump_provider_currently_active_ = mdp;
- bool dump_successful = mdp->DumpInto(pmd);
- dump_provider_currently_active_ = nullptr;
+ bool dump_successful = mdp->OnMemoryDump(pmd);
if (!dump_successful) {
- LOG(ERROR) << "The memory dumper " << mdp->GetFriendlyName()
- << " failed, possibly due to sandboxing (crbug.com/461788), "
- "disabling it for current process. Try restarting chrome "
- "with the --no-sandbox switch.";
- dump_providers_enabled_.erase(mdp);
+ LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
+ "(crbug.com/461788), disabling it for current process. Try "
+ "restarting chrome with the --no-sandbox switch.";
+ dump_providers_.find(mdp)->second.disabled = true;
}
return dump_successful;
}
// This is posted to arbitrary threads as a continuation of CreateProcessDump(),
-// when one or more MemoryDumpProvider(s) require the DumpInto() call to happen
-// on a different thread.
+// when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to
+// happen on a different thread.
void MemoryDumpManager::ContinueAsyncProcessDump(
MemoryDumpProvider* mdp,
scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
@@ -316,7 +343,7 @@
// Check if the MemoryDumpProvider is still there. It might have been
// destroyed and unregistered while hopping threads.
- if (dump_providers_enabled_.count(mdp))
+ if (dump_providers_.count(mdp))
InvokeDumpProviderLocked(mdp, pmd);
// Finalize the dump appending it to the trace if this was the last
@@ -341,18 +368,16 @@
// There is no point starting the tracing without a delegate.
if (!enabled || !delegate_) {
- dump_providers_enabled_.clear();
+ // Disable all the providers.
+ for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+ it->second.disabled = true;
return;
}
- // Merge the dictionary of allocator attributes from all dump providers
- // into the session state.
session_state_ = new MemoryDumpSessionState();
- for (const MemoryDumpProvider* mdp : dump_providers_registered_) {
- session_state_->allocators_attributes_type_info.Update(
- mdp->allocator_attributes_type_info());
- }
- dump_providers_enabled_ = dump_providers_registered_;
+ for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+ it->second.disabled = false;
+
subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
if (delegate_->IsCoordinatorProcess()) {
@@ -365,10 +390,16 @@
void MemoryDumpManager::OnTraceLogDisabled() {
AutoLock lock(lock_);
periodic_dump_timer_.Stop();
- dump_providers_enabled_.clear();
subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
session_state_ = nullptr;
}
+MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+ : task_runner(task_runner), disabled(false) {
+}
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
+}
+
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 371a47a..3645ac1 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -17,6 +17,9 @@
#include "base/trace_event/trace_event.h"
namespace base {
+
+class SingleThreadTaskRunner;
+
namespace trace_event {
namespace {
@@ -46,6 +49,12 @@
// MemoryDumpManager does NOT take memory ownership of |mdp|, which is
// expected to either be a singleton or unregister itself.
+ // If the optional |task_runner| argument is non-null, all the calls to the
+ // |mdp| will be issues on the given thread. Otherwise, the |mdp| should be
+ // able to handle calls on arbitrary threads.
+ void RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner);
void RegisterDumpProvider(MemoryDumpProvider* mdp);
void UnregisterDumpProvider(MemoryDumpProvider* mdp);
@@ -65,12 +74,6 @@
void OnTraceLogEnabled() override;
void OnTraceLogDisabled() override;
- // Returns the MemoryDumpProvider which is currently being dumping into a
- // ProcessMemoryDump via DumpInto(...) if any, nullptr otherwise.
- MemoryDumpProvider* dump_provider_currently_active() const {
- return dump_provider_currently_active_;
- }
-
// Returns the MemoryDumpSessionState object, which is shared by all the
// ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
// session lifetime.
@@ -79,6 +82,17 @@
}
private:
+ // Descriptor struct used to hold information about registered MDPs. It is
+ // deliberately copyable, in order to allow to be used as hash_map value.
+ struct MemoryDumpProviderInfo {
+ MemoryDumpProviderInfo(
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+ ~MemoryDumpProviderInfo();
+
+ scoped_refptr<SingleThreadTaskRunner> task_runner; // Optional.
+ bool disabled; // For fail-safe logic (auto-disable failing MDPs).
+ };
+
friend struct DefaultDeleter<MemoryDumpManager>; // For the testing instance.
friend struct DefaultSingletonTraits<MemoryDumpManager>;
friend class MemoryDumpManagerDelegate;
@@ -102,11 +116,7 @@
MemoryDumpProvider* mdp,
scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
- hash_set<MemoryDumpProvider*> dump_providers_registered_; // Not owned.
- hash_set<MemoryDumpProvider*> dump_providers_enabled_; // Not owned.
-
- // TODO(primiano): this is required only until crbug.com/466121 gets fixed.
- MemoryDumpProvider* dump_provider_currently_active_; // Not owned.
+ hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
// Shared among all the PMDs to keep state scoped to the tracing session.
scoped_refptr<MemoryDumpSessionState> session_state_;
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 589c406..1da9429 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -81,44 +81,35 @@
class MockDumpProvider : public MemoryDumpProvider {
public:
- MockDumpProvider() {}
+ MockDumpProvider() : last_session_state_(nullptr) {}
+ // Ctor used by the RespectTaskRunnerAffinity test.
explicit MockDumpProvider(
const scoped_refptr<SingleThreadTaskRunner>& task_runner)
- : MemoryDumpProvider(task_runner) {}
+ : last_session_state_(nullptr), task_runner_(task_runner) {}
- // Ctor for the SharedSessionState test.
- explicit MockDumpProvider(const std::string& id) {
- DeclareAllocatorAttribute("allocator" + id, "attr" + id, "type" + id);
- }
+ virtual ~MockDumpProvider() {}
- MOCK_METHOD1(DumpInto, bool(ProcessMemoryDump* pmd));
+ MOCK_METHOD1(OnMemoryDump, bool(ProcessMemoryDump* pmd));
- // DumpInto() override for the ActiveDumpProviderConsistency test.
- bool DumpIntoAndCheckDumpProviderCurrentlyActive(ProcessMemoryDump* pmd) {
- EXPECT_EQ(
- this,
- MemoryDumpManager::GetInstance()->dump_provider_currently_active());
+ // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
+ bool OnMemoryDump_CheckTaskRunner(ProcessMemoryDump* pmd) {
+ EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
return true;
}
- // DumpInto() override for the RespectTaskRunnerAffinity test.
- bool DumpIntoAndCheckTaskRunner(ProcessMemoryDump* pmd) {
- EXPECT_TRUE(task_runner()->RunsTasksOnCurrentThread());
+ // OnMemoryDump() override for the SharedSessionState test.
+ bool OnMemoryDump_CheckSessionState(ProcessMemoryDump* pmd) {
+ MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
+ if (last_session_state_)
+ EXPECT_EQ(last_session_state_, cur_session_state);
+ last_session_state_ = cur_session_state;
return true;
}
- // DumpInto() override for the SharedSessionState test.
- bool DumpIntoAndCheckSessionState(ProcessMemoryDump* pmd) {
- EXPECT_TRUE(pmd->session_state());
- const auto& attrs_type_info =
- pmd->session_state()->allocators_attributes_type_info;
- EXPECT_TRUE(attrs_type_info.Exists("allocator1", "attr1"));
- EXPECT_TRUE(attrs_type_info.Exists("allocator2", "attr2"));
- return true;
- }
-
- const char* GetFriendlyName() const override { return "MockDumpProvider"; }
+ private:
+ MemoryDumpSessionState* last_session_state_;
+ scoped_refptr<SingleThreadTaskRunner> task_runner_;
};
TEST_F(MemoryDumpManagerTest, SingleDumper) {
@@ -127,14 +118,14 @@
// Check that the dumper is not called if the memory category is not enabled.
EnableTracing("foo-and-bar-but-not-memory");
- EXPECT_CALL(mdp, DumpInto(_)).Times(0);
+ EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
DisableTracing();
// Now repeat enabling the memory category and check that the dumper is
// invoked this time.
EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp, DumpInto(_)).Times(3).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
for (int i = 0; i < 3; ++i)
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
DisableTracing();
@@ -143,22 +134,26 @@
// Finally check the unregister logic (no calls to the mdp after unregister).
EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp, DumpInto(_)).Times(0);
+ EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
TraceLog::GetInstance()->SetDisabled();
}
TEST_F(MemoryDumpManagerTest, SharedSessionState) {
- MockDumpProvider mdp1("1"); // Will declare an allocator property "attr1".
- MockDumpProvider mdp2("2"); // Will declare an allocator property "attr2".
+ MockDumpProvider mdp1;
+ MockDumpProvider mdp2;
mdm_->RegisterDumpProvider(&mdp1);
mdm_->RegisterDumpProvider(&mdp2);
EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, DumpInto(_)).Times(2).WillRepeatedly(
- Invoke(&mdp1, &MockDumpProvider::DumpIntoAndCheckSessionState));
- EXPECT_CALL(mdp2, DumpInto(_)).Times(2).WillRepeatedly(
- Invoke(&mdp2, &MockDumpProvider::DumpIntoAndCheckSessionState));
+ EXPECT_CALL(mdp1, OnMemoryDump(_))
+ .Times(2)
+ .WillRepeatedly(
+ Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+ EXPECT_CALL(mdp2, OnMemoryDump(_))
+ .Times(2)
+ .WillRepeatedly(
+ Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
for (int i = 0; i < 2; ++i)
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
@@ -173,8 +168,8 @@
// Enable only mdp1.
mdm_->RegisterDumpProvider(&mdp1);
EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
- EXPECT_CALL(mdp2, DumpInto(_)).Times(0);
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(0);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
DisableTracing();
@@ -182,16 +177,16 @@
mdm_->UnregisterDumpProvider(&mdp1);
mdm_->RegisterDumpProvider(&mdp2);
EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
- EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
DisableTracing();
// Enable both mdp1 and mdp2.
mdm_->RegisterDumpProvider(&mdp1);
EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
- EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
DisableTracing();
}
@@ -214,11 +209,11 @@
threads.back()->Start();
mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
MockDumpProvider* mdp = mdps.back();
- mdm_->RegisterDumpProvider(mdp);
- EXPECT_CALL(*mdp, DumpInto(_))
+ mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
+ EXPECT_CALL(*mdp, OnMemoryDump(_))
.Times(i)
.WillRepeatedly(
- Invoke(mdp, &MockDumpProvider::DumpIntoAndCheckTaskRunner));
+ Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
}
EnableTracing(kTraceCategory);
@@ -266,41 +261,16 @@
mdm_->RegisterDumpProvider(&mdp2);
EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
- EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
- EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
- EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
DisableTracing();
}
-// TODO(primiano): remove once crbug.com/466121 gets fixed.
-// Ascertains that calls to MDM::dump_provider_currently_active() actually
-// returns the MemoryDumpProvider currently active during the DumpInto() call.
-TEST_F(MemoryDumpManagerTest, ActiveDumpProviderConsistency) {
- MockDumpProvider mdp1;
- MockDumpProvider mdp2;
-
- mdm_->RegisterDumpProvider(&mdp1);
- mdm_->RegisterDumpProvider(&mdp2);
- EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, DumpInto(_))
- .Times(2)
- .WillRepeatedly(Invoke(
- &mdp1,
- &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
- EXPECT_CALL(mdp2, DumpInto(_))
- .Times(2)
- .WillRepeatedly(Invoke(
- &mdp2,
- &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
- DisableTracing();
-}
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/memory_dump_provider.cc b/base/trace_event/memory_dump_provider.cc
deleted file mode 100644
index a2d3889..0000000
--- a/base/trace_event/memory_dump_provider.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2015 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/trace_event/memory_dump_provider.h"
-
-#include "base/single_thread_task_runner.h"
-
-namespace base {
-namespace trace_event {
-
-MemoryDumpProvider::MemoryDumpProvider() {
-}
-
-MemoryDumpProvider::MemoryDumpProvider(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner)
- : task_runner_(task_runner) {
-}
-
-MemoryDumpProvider::~MemoryDumpProvider() {
-}
-
-void MemoryDumpProvider::DeclareAllocatorAttribute(
- const std::string& allocator_name,
- const std::string& attribute_name,
- const std::string& attribute_type) {
- allocator_attributes_type_info_.Set(
- allocator_name, attribute_name, attribute_type);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index 9ec7ad9..6e6551c 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -6,13 +6,9 @@
#define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
#include "base/base_export.h"
-#include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
+#include "base/macros.h"
namespace base {
-
-class SingleThreadTaskRunner;
-
namespace trace_event {
class ProcessMemoryDump;
@@ -21,45 +17,15 @@
class BASE_EXPORT MemoryDumpProvider {
public:
// Called by the MemoryDumpManager when generating memory dumps.
- // Returns: true if the |pmd| was successfully populated, false otherwise.
- virtual bool DumpInto(ProcessMemoryDump* pmd) = 0;
-
- virtual const char* GetFriendlyName() const = 0;
-
- const MemoryAllocatorAttributesTypeInfo& allocator_attributes_type_info()
- const {
- return allocator_attributes_type_info_;
- }
-
- // The dump provider can specify an optional thread affinity (in its
- // base constructor call). If |task_runner| is non empty, all the calls to
- // DumpInto are guaranteed to be posted to that TaskRunner.
- const scoped_refptr<SingleThreadTaskRunner>& task_runner() const {
- return task_runner_;
- }
+ // The embedder should return true if the |pmd| was successfully populated,
+ // false if something went wrong and the dump should be considered invalid.
+ // (Note, the MemoryDumpManager has a fail-safe logic which will disable the
+ // MemoryDumpProvider for the entire trace session if it fails consistently).
+ virtual bool OnMemoryDump(ProcessMemoryDump* pmd) = 0;
protected:
- // Default ctor: the MDP is not bound to any thread (must be a singleton).
- MemoryDumpProvider();
-
- // Use this ctor to ensure that DumpInto() is called always on the same thread
- // specified by |task_runner|.
- explicit MemoryDumpProvider(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner);
-
- virtual ~MemoryDumpProvider();
-
- void DeclareAllocatorAttribute(const std::string& allocator_name,
- const std::string& attribute_name,
- const std::string& attribute_type);
-
- private:
- // A map of attributes types (declared through DeclareAllocatorAttribute())
- // emitted by this allocator dumper.
- MemoryAllocatorAttributesTypeInfo allocator_attributes_type_info_;
-
- // (Optional) TaskRunner on which the DumpInfo call should be posted.
- scoped_refptr<SingleThreadTaskRunner> task_runner_;
+ MemoryDumpProvider() {}
+ virtual ~MemoryDumpProvider() {}
DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
};
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
index 38a6fe2..cf29b85 100644
--- a/base/trace_event/memory_dump_session_state.h
+++ b/base/trace_event/memory_dump_session_state.h
@@ -9,16 +9,16 @@
#include "base/base_export.h"
#include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
namespace base {
namespace trace_event {
+// Container for state variables that should be shared across all the memory
+// dumps in a tracing session.
class BASE_EXPORT MemoryDumpSessionState
: public RefCountedThreadSafe<MemoryDumpSessionState> {
public:
MemoryDumpSessionState();
- MemoryAllocatorAttributesTypeInfo allocators_attributes_type_info;
private:
friend class RefCountedThreadSafe<MemoryDumpSessionState>;
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 836d6ae..54fcad6 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -21,21 +21,17 @@
}
MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
- const std::string& allocator_name,
- const std::string& heap_name) {
- MemoryAllocatorDump* mad =
- new MemoryAllocatorDump(allocator_name, heap_name, this);
- DCHECK_EQ(0ul, allocator_dumps_.count(mad->GetAbsoluteName()));
+ const std::string& absolute_name) {
+ MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this);
+ DCHECK_EQ(0ul, allocator_dumps_.count(absolute_name));
allocator_dumps_storage_.push_back(mad);
- allocator_dumps_[mad->GetAbsoluteName()] = mad;
+ allocator_dumps_[absolute_name] = mad;
return mad;
}
MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
- const std::string& allocator_name,
- const std::string& heap_name) const {
- auto it = allocator_dumps_.find(
- MemoryAllocatorDump::GetAbsoluteName(allocator_name, heap_name));
+ const std::string& absolute_name) const {
+ auto it = allocator_dumps_.find(absolute_name);
return it == allocator_dumps_.end() ? nullptr : it->second;
}
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index bd9c543..889356d 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -52,24 +52,16 @@
// Creates a new MemoryAllocatorDump with the given name and returns the
// empty object back to the caller.
// Arguments:
- // allocator_name: a name that univocally identifies allocator dumps
- // produced by this provider. It acts as a type w.r.t. the allocator
- // attributes, in the sense that all the MAD with the same allocator_name
- // are expected to have the same attributes.
- // heap_name, either:
- // - kRootHeap: if the allocator has only one default heap.
- // - a string identifing a heap name (e.g., isolate1, isolate2 ...). It is
- // possible to specify nesting by using a path-like string (e.g.,
- // isolate1/heap_spaceX, isolate1/heap_spaceY, isolate2/heap_spaceX).
- // The tuple (|allocator_name|, |heap_name|) is unique inside a PMD.
+ // absolute_name: a name that uniquely identifies allocator dumps produced
+ // by this provider. It is possible to specify nesting by using a
+ // path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
+ // Leading or trailing slashes are not allowed.
// ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
- MemoryAllocatorDump* CreateAllocatorDump(const std::string& allocator_name,
- const std::string& heap_name);
+ MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
// Looks up a MemoryAllocatorDump given its allocator and heap names, or
// nullptr if not found.
- MemoryAllocatorDump* GetAllocatorDump(const std::string& allocator_name,
- const std::string& heap_name) const;
+ MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
// Returns the map of the MemoryAllocatorDumps added to this dump.
const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
index d728bd3..680fa29 100644
--- a/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -15,10 +15,6 @@
namespace base {
namespace trace_event {
-namespace {
-const char kDumperFriendlyName[] = "ProcessMemoryMaps";
-}
-
#if defined(OS_LINUX) || defined(OS_ANDROID)
// static
std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
@@ -167,7 +163,7 @@
// Called at trace dump point time. Creates a snapshot the memory maps for the
// current process.
-bool ProcessMemoryMapsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool ProcessMemoryMapsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
uint32 res = 0;
#if defined(OS_LINUX) || defined(OS_ANDROID)
@@ -189,9 +185,5 @@
return false;
}
-const char* ProcessMemoryMapsDumpProvider::GetFriendlyName() const {
- return kDumperFriendlyName;
-}
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
index 0d30db2..c73c4d2 100644
--- a/base/trace_event/process_memory_maps_dump_provider.h
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -20,8 +20,7 @@
static ProcessMemoryMapsDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool DumpInto(ProcessMemoryDump* pmd) override;
- const char* GetFriendlyName() const override;
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index 2ce2504..e45d30a 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -118,21 +118,21 @@
std::ifstream non_existent_file("/tmp/does-not-exist");
ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
CHECK_EQ(false, non_existent_file.good());
- pmmdp->DumpInto(&pmd_invalid);
+ pmmdp->OnMemoryDump(&pmd_invalid);
ASSERT_FALSE(pmd_invalid.has_process_mmaps());
// Emulate an empty /proc/self/smaps.
std::ifstream empty_file("/dev/null");
ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
CHECK_EQ(true, empty_file.good());
- pmmdp->DumpInto(&pmd_invalid);
+ pmmdp->OnMemoryDump(&pmd_invalid);
ASSERT_FALSE(pmd_invalid.has_process_mmaps());
// Parse the 1st smaps file.
ProcessMemoryDump pmd_1(nullptr /* session_state */);
std::istringstream test_smaps_1(kTestSmaps1);
ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
- pmmdp->DumpInto(&pmd_1);
+ pmmdp->OnMemoryDump(&pmd_1);
ASSERT_TRUE(pmd_1.has_process_mmaps());
const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
ASSERT_EQ(2UL, regions_1.size());
@@ -157,7 +157,7 @@
ProcessMemoryDump pmd_2(nullptr /* session_state */);
std::istringstream test_smaps_2(kTestSmaps2);
ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
- pmmdp->DumpInto(&pmd_2);
+ pmmdp->OnMemoryDump(&pmd_2);
ASSERT_TRUE(pmd_2.has_process_mmaps());
const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
ASSERT_EQ(1UL, regions_2.size());
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
index 125be38..06b537c 100644
--- a/base/trace_event/process_memory_totals_dump_provider.cc
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -16,8 +16,6 @@
namespace {
-const char kDumperFriendlyName[] = "ProcessMemoryTotals";
-
ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
#if !defined(OS_MACOSX) || defined(OS_IOS)
return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
@@ -44,7 +42,7 @@
// Called at trace dump point time. Creates a snapshot the memory counters for
// the current process.
-bool ProcessMemoryTotalsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
const uint64 rss_bytes = rss_bytes_for_testing
? rss_bytes_for_testing
: process_metrics_->GetWorkingSetSize();
@@ -58,9 +56,5 @@
return false;
}
-const char* ProcessMemoryTotalsDumpProvider::GetFriendlyName() const {
- return kDumperFriendlyName;
-}
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h
index 8dae966..6c86eb6 100644
--- a/base/trace_event/process_memory_totals_dump_provider.h
+++ b/base/trace_event/process_memory_totals_dump_provider.h
@@ -22,8 +22,7 @@
static ProcessMemoryTotalsDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool DumpInto(ProcessMemoryDump* pmd) override;
- const char* GetFriendlyName() const override;
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
index ffaf177..f9bb6c0 100644
--- a/base/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -17,13 +17,13 @@
scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
- pmtdp->DumpInto(pmd_before.get());
+ pmtdp->OnMemoryDump(pmd_before.get());
// Pretend that the RSS of the process increased of +1M.
const size_t kAllocSize = 1048576;
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
- pmtdp->DumpInto(pmd_after.get());
+ pmtdp->OnMemoryDump(pmd_after.get());
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index 9bbd172..9a072e4 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -6,13 +6,10 @@
'trace_event_sources' : [
'trace_event/java_heap_dump_provider_android.cc',
'trace_event/java_heap_dump_provider_android.h',
- 'trace_event/memory_allocator_attributes_type_info.cc',
- 'trace_event/memory_allocator_attributes_type_info.h',
'trace_event/memory_allocator_dump.cc',
'trace_event/memory_allocator_dump.h',
'trace_event/memory_dump_manager.cc',
'trace_event/memory_dump_manager.h',
- 'trace_event/memory_dump_provider.cc',
'trace_event/memory_dump_provider.h',
'trace_event/memory_dump_request_args.h',
'trace_event/memory_dump_session_state.cc',
@@ -56,7 +53,7 @@
}],
],
'trace_event_test_sources' : [
- 'trace_event/memory_allocator_attributes_type_info_unittest.cc',
+ 'trace_event/java_heap_dump_provider_android_unittest.cc',
'trace_event/memory_allocator_dump_unittest.cc',
'trace_event/memory_dump_manager_unittest.cc',
'trace_event/process_memory_maps_dump_provider_unittest.cc',
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index e0249f5..86f959f 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -709,6 +709,13 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(category_group, name, \
+ id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+
// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 2
// associated arguments. If the category is not enabled, then this does nothing.
#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
@@ -716,6 +723,13 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(category_group, name, \
+ id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+
// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
// with 2 associated arguments. If the category is not enabled, then this
// does nothing.
@@ -1081,6 +1095,7 @@
#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned char>(1 << 4))
#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast<unsigned char>(1 << 6))
#define TRACE_EVENT_FLAG_SCOPE_MASK (static_cast<unsigned char>( \
TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
index bcba436..26bd0c7 100644
--- a/base/trace_event/trace_event_android.cc
+++ b/base/trace_event/trace_event_android.cc
@@ -114,7 +114,7 @@
Thread end_chrome_tracing_thread("end_chrome_tracing");
WaitableEvent complete_event(false, false);
end_chrome_tracing_thread.Start();
- end_chrome_tracing_thread.message_loop()->PostTask(
+ end_chrome_tracing_thread.task_runner()->PostTask(
FROM_HERE, base::Bind(&EndChromeTracing, Unretained(this),
Unretained(&complete_event)));
complete_event.Wait();
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index cbeeeab..5ae7fb2 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -14,8 +14,8 @@
#include "base/format_macros.h"
#include "base/json/string_escape.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
#include "base/process/process_metrics.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -28,6 +28,7 @@
#include "base/synchronization/waitable_event.h"
#include "base/sys_info.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/worker_pool.h"
@@ -741,6 +742,11 @@
StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
}
+ // Output async tts marker field if flag is set.
+ if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) {
+ StringAppendF(out, ", \"use_async_tts\":1");
+ }
+
// If id_ is set, print it out as a hex string so we don't loose any
// bits (it might be a 64-bit pointer).
if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
@@ -1406,7 +1412,7 @@
AutoLock lock(lock_);
// Can't enable tracing when Flush() is in progress.
- DCHECK(!flush_message_loop_proxy_.get());
+ DCHECK(!flush_task_runner_);
InternalTraceOptions new_options =
GetInternalOptionsFromTraceOptions(options);
@@ -1680,9 +1686,9 @@
}
// Flush() works as the following:
-// 1. Flush() is called in threadA whose message loop is saved in
-// flush_message_loop_proxy_;
-// 2. If thread_message_loops_ is not empty, threadA posts task to each message
+// 1. Flush() is called in thread A whose task runner is saved in
+// flush_task_runner_;
+// 2. If thread_message_loops_ is not empty, thread A posts task to each message
// loop to flush the thread local buffers; otherwise finish the flush;
// 3. FlushCurrentThread() deletes the thread local event buffer:
// - The last batch of events of the thread are flushed into the main buffer;
@@ -1710,9 +1716,11 @@
thread_message_loop_task_runners;
{
AutoLock lock(lock_);
- DCHECK(!flush_message_loop_proxy_.get());
- flush_message_loop_proxy_ = MessageLoopProxy::current();
- DCHECK(!thread_message_loops_.size() || flush_message_loop_proxy_.get());
+ DCHECK(!flush_task_runner_);
+ flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
+ ? ThreadTaskRunnerHandle::Get()
+ : nullptr;
+ DCHECK_IMPLIES(thread_message_loops_.size(), flush_task_runner_);
flush_output_callback_ = cb;
if (thread_shared_chunk_) {
@@ -1735,7 +1743,7 @@
FROM_HERE,
Bind(&TraceLog::FlushCurrentThread, Unretained(this), generation));
}
- flush_message_loop_proxy_->PostDelayedTask(
+ flush_task_runner_->PostDelayedTask(
FROM_HERE,
Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation),
TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
@@ -1789,7 +1797,7 @@
UseNextTraceBuffer();
thread_message_loops_.clear();
- flush_message_loop_proxy_ = NULL;
+ flush_task_runner_ = NULL;
flush_output_callback = flush_output_callback_;
flush_output_callback_.Reset();
}
@@ -1812,7 +1820,7 @@
void TraceLog::FlushCurrentThread(int generation) {
{
AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get()) {
+ if (!CheckGeneration(generation) || !flush_task_runner_) {
// This is late. The corresponding flush has finished.
return;
}
@@ -1822,19 +1830,18 @@
delete thread_local_event_buffer_.Get();
AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get() ||
+ if (!CheckGeneration(generation) || !flush_task_runner_ ||
thread_message_loops_.size())
return;
- flush_message_loop_proxy_->PostTask(
- FROM_HERE,
- Bind(&TraceLog::FinishFlush, Unretained(this), generation));
+ flush_task_runner_->PostTask(
+ FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation));
}
void TraceLog::OnFlushTimeout(int generation) {
{
AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get()) {
+ if (!CheckGeneration(generation) || !flush_task_runner_) {
// Flush has finished before timeout.
return;
}
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 33a85c9..50d33ca 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -18,6 +18,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_vector.h"
#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@@ -798,8 +799,8 @@
ThreadLocalBoolean thread_is_in_trace_event_;
// Contains the message loops of threads that have had at least one event
- // added into the local event buffer. Not using MessageLoopProxy because we
- // need to know the life time of the message loops.
+ // added into the local event buffer. Not using SingleThreadTaskRunner
+ // because we need to know the life time of the message loops.
hash_set<MessageLoop*> thread_message_loops_;
// For events which can't be added into the thread local buffer, e.g. events
@@ -809,7 +810,7 @@
// Set when asynchronous Flush is in progress.
OutputCallback flush_output_callback_;
- scoped_refptr<MessageLoopProxy> flush_message_loop_proxy_;
+ scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
subtle::AtomicWord generation_;
bool use_worker_thread_;
diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc
index 2bf6d38..ab8ba0d 100644
--- a/base/trace_event/trace_event_memory.cc
+++ b/base/trace_event/trace_event_memory.cc
@@ -6,9 +6,10 @@
#include "base/debug/leak_annotations.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_local_storage.h"
@@ -144,11 +145,11 @@
//////////////////////////////////////////////////////////////////////////////
TraceMemoryController::TraceMemoryController(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ scoped_refptr<SingleThreadTaskRunner> task_runner,
HeapProfilerStartFunction heap_profiler_start_function,
HeapProfilerStopFunction heap_profiler_stop_function,
GetHeapProfileFunction get_heap_profile_function)
- : message_loop_proxy_(message_loop_proxy),
+ : task_runner_(task_runner.Pass()),
heap_profiler_start_function_(heap_profiler_start_function),
heap_profiler_stop_function_(heap_profiler_stop_function),
get_heap_profile_function_(get_heap_profile_function),
@@ -174,10 +175,9 @@
if (!enabled)
return;
DVLOG(1) << "OnTraceLogEnabled";
- message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&TraceMemoryController::StartProfiling,
- weak_factory_.GetWeakPtr()));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&TraceMemoryController::StartProfiling,
+ weak_factory_.GetWeakPtr()));
}
void TraceMemoryController::OnTraceLogDisabled() {
@@ -185,10 +185,9 @@
// called, so we cannot tell if it was enabled before. Always try to turn
// off profiling.
DVLOG(1) << "OnTraceLogDisabled";
- message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&TraceMemoryController::StopProfiling,
- weak_factory_.GetWeakPtr()));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&TraceMemoryController::StopProfiling,
+ weak_factory_.GetWeakPtr()));
}
void TraceMemoryController::StartProfiling() {
diff --git a/base/trace_event/trace_event_memory.h b/base/trace_event/trace_event_memory.h
index 8e70020..e2b3ae9 100644
--- a/base/trace_event/trace_event_memory.h
+++ b/base/trace_event/trace_event_memory.h
@@ -20,7 +20,7 @@
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
namespace trace_event {
@@ -35,15 +35,14 @@
typedef void (*HeapProfilerStopFunction)();
typedef char* (*GetHeapProfileFunction)();
- // |message_loop_proxy| must be a proxy to the primary thread for the client
+ // |task_runner| must be a task runner for the primary thread for the client
// process, e.g. the UI thread in a browser. The function pointers must be
// pointers to tcmalloc heap profiling functions; by avoiding direct calls to
// these functions we avoid a dependency on third_party/tcmalloc from base.
- TraceMemoryController(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
- HeapProfilerStartFunction heap_profiler_start_function,
- HeapProfilerStopFunction heap_profiler_stop_function,
- GetHeapProfileFunction get_heap_profile_function);
+ TraceMemoryController(scoped_refptr<SingleThreadTaskRunner> task_runner,
+ HeapProfilerStartFunction heap_profiler_start_function,
+ HeapProfilerStopFunction heap_profiler_stop_function,
+ GetHeapProfileFunction get_heap_profile_function);
virtual ~TraceMemoryController();
// base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
@@ -65,7 +64,7 @@
bool IsTimerRunningForTest() const;
// Ensures the observer starts and stops tracing on the primary thread.
- scoped_refptr<MessageLoopProxy> message_loop_proxy_;
+ scoped_refptr<SingleThreadTaskRunner> task_runner_;
// Pointers to tcmalloc heap profiling functions. Allows this class to use
// tcmalloc functions without introducing a dependency from base to tcmalloc.
diff --git a/base/trace_event/trace_event_memory_unittest.cc b/base/trace_event/trace_event_memory_unittest.cc
index 4732733..781a054 100644
--- a/base/trace_event/trace_event_memory_unittest.cc
+++ b/base/trace_event/trace_event_memory_unittest.cc
@@ -7,7 +7,6 @@
#include <sstream>
#include <string>
-#include "base/message_loop/message_loop.h"
#include "base/trace_event/trace_event_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -40,12 +39,9 @@
EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
// Creating a controller adds it to the TraceLog observer list.
- scoped_ptr<TraceMemoryController> controller(
- new TraceMemoryController(
- message_loop.message_loop_proxy(),
- ::HeapProfilerWithPseudoStackStart,
- ::HeapProfilerStop,
- ::GetHeapProfile));
+ scoped_ptr<TraceMemoryController> controller(new TraceMemoryController(
+ message_loop.task_runner(), ::HeapProfilerWithPseudoStackStart,
+ ::HeapProfilerStop, ::GetHeapProfile));
EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
EXPECT_TRUE(
TraceLog::GetInstance()->HasEnabledStateObserver(controller.get()));
diff --git a/base/trace_event/trace_event_system_stats_monitor_unittest.cc b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
index 995f53b..03dff59 100644
--- a/base/trace_event/trace_event_system_stats_monitor_unittest.cc
+++ b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
@@ -7,7 +7,6 @@
#include <sstream>
#include <string>
-#include "base/message_loop/message_loop.h"
#include "base/trace_event/trace_event_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,8 +35,7 @@
// Creating a system stats monitor adds it to the TraceLog observer list.
scoped_ptr<TraceEventSystemStatsMonitor> system_stats_monitor(
- new TraceEventSystemStatsMonitor(
- message_loop.message_loop_proxy()));
+ new TraceEventSystemStatsMonitor(message_loop.task_runner()));
EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
EXPECT_TRUE(
TraceLog::GetInstance()->HasEnabledStateObserver(
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 0d3b091..17953e7 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -9,10 +9,12 @@
#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/location.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
@@ -95,10 +97,9 @@
WaitableEvent flush_complete_event(false, false);
Thread flush_thread("flush");
flush_thread.Start();
- flush_thread.message_loop()->PostTask(FROM_HERE,
- base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
- base::Unretained(this),
- &flush_complete_event));
+ flush_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
+ base::Unretained(this), &flush_complete_event));
flush_complete_event.Wait();
}
@@ -1424,7 +1425,7 @@
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, base::Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
thread.Stop();
@@ -1445,9 +1446,9 @@
threads[i] = new Thread(StringPrintf("Thread %d", i));
task_complete_events[i] = new WaitableEvent(false, false);
threads[i]->Start();
- threads[i]->message_loop()->PostTask(
- FROM_HERE, base::Bind(&TraceManyInstantEvents,
- i, num_events, task_complete_events[i]));
+ threads[i]->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TraceManyInstantEvents, i, num_events,
+ task_complete_events[i]));
}
for (int i = 0; i < num_threads; i++) {
@@ -1493,9 +1494,9 @@
task_complete_events[i] = new WaitableEvent(false, false);
threads[i]->Start();
thread_ids[i] = threads[i]->thread_id();
- threads[i]->message_loop()->PostTask(
- FROM_HERE, base::Bind(&TraceManyInstantEvents,
- i, kNumEvents, task_complete_events[i]));
+ threads[i]->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
+ task_complete_events[i]));
}
for (int i = 0; i < kNumThreads; i++) {
task_complete_events[i]->Wait();
@@ -2725,17 +2726,17 @@
Thread thread("1");
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceLog::SetCurrentThreadBlocksMessageLoop,
Unretained(TraceLog::GetInstance())));
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
WaitableEvent task_start_event(false, false);
WaitableEvent task_stop_event(false, false);
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
task_start_event.Wait();
@@ -2796,15 +2797,15 @@
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
WaitableEvent task_start_event(false, false);
WaitableEvent task_stop_event(false, false);
- thread.message_loop()->PostTask(
- FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped,
- &task_start_event, &task_stop_event));
+ thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped, &task_start_event,
+ &task_stop_event));
task_start_event.Wait();
EndTraceAndFlush();
@@ -2821,14 +2822,14 @@
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
task_complete_event.Reset();
WaitableEvent task_start_event(false, false);
WaitableEvent task_stop_event(false, false);
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
task_start_event.Wait();
@@ -2843,7 +2844,7 @@
// executed in the thread before continuing.
task_start_event.Reset();
task_stop_event.Reset();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
task_start_event.Wait();
task_stop_event.Signal();
@@ -2852,7 +2853,7 @@
// TraceLog should discover the generation mismatch and recover the thread
// local buffer for the thread without any error.
BeginTrace();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
task_complete_event.Reset();
diff --git a/base/trace_event/winheap_dump_provider_win.cc b/base/trace_event/winheap_dump_provider_win.cc
index 3a4fd87..e1e9bcf 100644
--- a/base/trace_event/winheap_dump_provider_win.cc
+++ b/base/trace_event/winheap_dump_provider_win.cc
@@ -13,21 +13,21 @@
namespace {
-const char kDumperFriendlyName[] = "winheap";
-
// Report a heap dump to a process memory dump. The |heap_info| structure
-// contains the information about this heap, and |heap_name| will be used to
-// represent it in the report.
+// contains the information about this heap, and |dump_absolute_name| will be
+// used to represent it in the report.
bool ReportHeapDump(ProcessMemoryDump* pmd,
const WinHeapInfo& heap_info,
- const std::string& heap_name) {
- MemoryAllocatorDump* dump =
- pmd->CreateAllocatorDump(kDumperFriendlyName, heap_name);
+ const std::string& dump_absolute_name) {
+ MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_absolute_name);
if (!dump)
return false;
- dump->set_physical_size_in_bytes(heap_info.committed_size);
- dump->set_allocated_objects_count(heap_info.block_count);
- dump->set_allocated_objects_size_in_bytes(heap_info.allocated_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, heap_info.committed_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, heap_info.allocated_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kUnitsObjects, heap_info.block_count);
return true;
}
@@ -38,7 +38,7 @@
LeakySingletonTraits<WinHeapDumpProvider>>::get();
}
-bool WinHeapDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool WinHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
// Retrieves the number of heaps in the current process.
DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
WinHeapInfo all_heap_info = {0};
@@ -68,16 +68,12 @@
all_heap_info.block_count += heap_info.block_count;
}
// Report the heap dump.
- if (!ReportHeapDump(pmd, all_heap_info, MemoryAllocatorDump::kRootHeap))
+ if (!ReportHeapDump(pmd, all_heap_info, "winheap"))
return false;
return true;
}
-const char* WinHeapDumpProvider::GetFriendlyName() const {
- return kDumperFriendlyName;
-}
-
bool WinHeapDumpProvider::GetHeapInformation(
WinHeapInfo* heap_info,
const std::set<void*>& block_to_skip) {
diff --git a/base/trace_event/winheap_dump_provider_win.h b/base/trace_event/winheap_dump_provider_win.h
index 8abac47..99239a0 100644
--- a/base/trace_event/winheap_dump_provider_win.h
+++ b/base/trace_event/winheap_dump_provider_win.h
@@ -29,8 +29,7 @@
static WinHeapDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool DumpInto(ProcessMemoryDump* pmd) override;
- const char* GetFriendlyName() const override;
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<WinHeapDumpProvider>;
diff --git a/base/trace_event/winheap_dump_provider_win_unittest.cc b/base/trace_event/winheap_dump_provider_win_unittest.cc
index 99da18a..2309802 100644
--- a/base/trace_event/winheap_dump_provider_win_unittest.cc
+++ b/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -13,14 +13,14 @@
namespace base {
namespace trace_event {
-TEST(WinHeapDumpProviderTest, DumpInto) {
+TEST(WinHeapDumpProviderTest, OnMemoryDump) {
ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
WinHeapDumpProvider* winheap_dump_provider =
WinHeapDumpProvider::GetInstance();
ASSERT_NE(static_cast<WinHeapDumpProvider*>(nullptr), winheap_dump_provider);
- ASSERT_TRUE(winheap_dump_provider->DumpInto(&pmd));
+ ASSERT_TRUE(winheap_dump_provider->OnMemoryDump(&pmd));
}
} // namespace trace_event
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index a60e260..9029f4f 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -28,19 +28,13 @@
namespace tracked_objects {
namespace {
-// TODO(jar): Evaluate the perf impact of enabling this. If the perf impact is
-// negligible, enable by default.
-// Flag to compile out parent-child link recording.
-const bool kTrackParentChildLinks = false;
-
// When ThreadData is first initialized, should we start in an ACTIVE state to
// record all of the startup-time tasks, or should we start up DEACTIVATED, so
// that we only record after parsing the command line flag --enable-tracking.
// Note that the flag may force either state, so this really controls only the
-// period of time up until that flag is parsed. If there is no flag seen, then
+// period of time up until that flag is parsed. If there is no flag seen, then
// this state may prevail for much or all of the process lifetime.
-const ThreadData::Status kInitialStartupState =
- ThreadData::PROFILING_CHILDREN_ACTIVE;
+const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE;
// Control whether an alternate time source (Now() function) is supported by
// the ThreadData class. This compile time flag should be set to true if we
@@ -61,9 +55,10 @@
// State of the profiler timing enabledness.
base::subtle::Atomic32 g_profiler_timing_enabled = UNDEFINED_TIMING;
-// Returns whether profiler timing is enabled. The default is true, but this may
-// be overridden by a command-line flag. Some platforms may programmatically set
-// this command-line flag to the "off" value if it's not specified.
+// Returns whether profiler timing is enabled. The default is true, but this
+// may be overridden by a command-line flag. Some platforms may
+// programmatically set this command-line flag to the "off" value if it's not
+// specified.
// This in turn can be overridden by explicitly calling
// ThreadData::EnableProfilerTiming, say, based on a field trial.
inline bool IsProfilerTimingEnabled() {
@@ -92,13 +87,40 @@
//------------------------------------------------------------------------------
// DeathData tallies durations when a death takes place.
-DeathData::DeathData() {
- Clear();
+DeathData::DeathData()
+ : count_(0),
+ sample_probability_count_(0),
+ run_duration_sum_(0),
+ queue_duration_sum_(0),
+ run_duration_max_(0),
+ queue_duration_max_(0),
+ run_duration_sample_(0),
+ queue_duration_sample_(0),
+ last_phase_snapshot_(nullptr) {
}
-DeathData::DeathData(int count) {
- Clear();
- count_ = count;
+DeathData::DeathData(const DeathData& other)
+ : count_(other.count_),
+ sample_probability_count_(other.sample_probability_count_),
+ run_duration_sum_(other.run_duration_sum_),
+ queue_duration_sum_(other.queue_duration_sum_),
+ run_duration_max_(other.run_duration_max_),
+ queue_duration_max_(other.queue_duration_max_),
+ run_duration_sample_(other.run_duration_sample_),
+ queue_duration_sample_(other.queue_duration_sample_),
+ last_phase_snapshot_(nullptr) {
+ // This constructor will be used by std::map when adding new DeathData values
+ // to the map. At that point, last_phase_snapshot_ is still NULL, so we don't
+ // need to worry about ownership transfer.
+ DCHECK(other.last_phase_snapshot_ == nullptr);
+}
+
+DeathData::~DeathData() {
+ while (last_phase_snapshot_) {
+ const DeathDataPhaseSnapshot* snapshot = last_phase_snapshot_;
+ last_phase_snapshot_ = snapshot->prev;
+ delete snapshot;
+ }
}
// TODO(jar): I need to see if this macro to optimize branching is worth using.
@@ -117,6 +139,12 @@
// We'll just clamp at INT_MAX, but we should note this in the UI as such.
if (count_ < INT_MAX)
++count_;
+
+ int sample_probability_count = sample_probability_count_;
+ if (sample_probability_count < INT_MAX)
+ ++sample_probability_count;
+ sample_probability_count_ = sample_probability_count;
+
queue_duration_sum_ += queue_duration;
run_duration_sum_ += run_duration;
@@ -125,14 +153,16 @@
if (run_duration_max_ < run_duration)
run_duration_max_ = run_duration;
- // Take a uniformly distributed sample over all durations ever supplied.
- // The probability that we (instead) use this new sample is 1/count_. This
- // results in a completely uniform selection of the sample (at least when we
- // don't clamp count_... but that should be inconsequentially likely).
- // We ignore the fact that we correlated our selection of a sample to the run
- // and queue times (i.e., we used them to generate random_number).
- CHECK_GT(count_, 0);
- if (0 == (random_number % count_)) {
+ // Take a uniformly distributed sample over all durations ever supplied during
+ // the current profiling phase.
+ // The probability that we (instead) use this new sample is
+ // 1/sample_probability_count_. This results in a completely uniform selection
+ // of the sample (at least when we don't clamp sample_probability_count_...
+ // but that should be inconsequentially likely). We ignore the fact that we
+ // correlated our selection of a sample to the run and queue times (i.e., we
+ // used them to generate random_number).
+ CHECK_GT(sample_probability_count, 0);
+ if (0 == (random_number % sample_probability_count)) {
queue_duration_sample_ = queue_duration;
run_duration_sample_ = run_duration;
}
@@ -160,14 +190,43 @@
return queue_duration_sample_;
}
-void DeathData::Clear() {
- count_ = 0;
- run_duration_sum_ = 0;
+const DeathDataPhaseSnapshot* DeathData::last_phase_snapshot() const {
+ return last_phase_snapshot_;
+}
+
+void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
+ // Snapshotting and storing current state.
+ last_phase_snapshot_ = new DeathDataPhaseSnapshot(
+ profiling_phase, count_, run_duration_sum_, run_duration_max_,
+ run_duration_sample_, queue_duration_sum_, queue_duration_max_,
+ queue_duration_sample_, last_phase_snapshot_);
+
+ // Not touching fields for which a delta can be computed by comparing with a
+ // snapshot from the previous phase. Resetting other fields. Sample values
+ // will be reset upon next death recording because sample_probability_count_
+ // is set to 0.
+ // We avoid resetting to 0 in favor of deltas whenever possible. The reason
+ // is that for incrementable fields, resetting to 0 from the snapshot thread
+ // potentially in parallel with incrementing in the death thread may result in
+ // significant data corruption that has a potential to grow with time. Not
+ // resetting incrementable fields and using deltas will cause any
+ // off-by-little corruptions to be likely fixed at the next snapshot.
+ // The max values are not incrementable, and cannot be deduced using deltas
+ // for a given phase. Hence, we have to reset them to 0. But the potential
+ // damage is limited to getting the previous phase's max to apply for the next
+ // phase, and the error doesn't have a potential to keep growing with new
+ // resets.
+ // sample_probability_count_ is incrementable, but must be reset to 0 at the
+ // phase end, so that we start a new uniformly randomized sample selection
+ // after the reset. Corruptions due to race conditions are possible, but the
+ // damage is limited to selecting a wrong sample, which is not something that
+ // can cause accumulating or cascading effects.
+ // If there were no corruptions caused by race conditions, we never send a
+ // sample for the previous phase in the next phase's snapshot because
+ // ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count.
+ sample_probability_count_ = 0;
run_duration_max_ = 0;
- run_duration_sample_ = 0;
- queue_duration_sum_ = 0;
queue_duration_max_ = 0;
- queue_duration_sample_ = 0;
}
//------------------------------------------------------------------------------
@@ -181,20 +240,34 @@
queue_duration_sample(-1) {
}
-DeathDataSnapshot::DeathDataSnapshot(
- const tracked_objects::DeathData& death_data)
- : count(death_data.count()),
- run_duration_sum(death_data.run_duration_sum()),
- run_duration_max(death_data.run_duration_max()),
- run_duration_sample(death_data.run_duration_sample()),
- queue_duration_sum(death_data.queue_duration_sum()),
- queue_duration_max(death_data.queue_duration_max()),
- queue_duration_sample(death_data.queue_duration_sample()) {
+DeathDataSnapshot::DeathDataSnapshot(int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample)
+ : count(count),
+ run_duration_sum(run_duration_sum),
+ run_duration_max(run_duration_max),
+ run_duration_sample(run_duration_sample),
+ queue_duration_sum(queue_duration_sum),
+ queue_duration_max(queue_duration_max),
+ queue_duration_sample(queue_duration_sample) {
}
DeathDataSnapshot::~DeathDataSnapshot() {
}
+DeathDataSnapshot DeathDataSnapshot::Delta(
+ const DeathDataSnapshot& older) const {
+ return DeathDataSnapshot(count - older.count,
+ run_duration_sum - older.run_duration_sum,
+ run_duration_max, run_duration_sample,
+ queue_duration_sum - older.queue_duration_sum,
+ queue_duration_max, queue_duration_sample);
+}
+
//------------------------------------------------------------------------------
BirthOnThread::BirthOnThread(const Location& location,
const ThreadData& current)
@@ -206,8 +279,7 @@
BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
}
-BirthOnThreadSnapshot::BirthOnThreadSnapshot(
- const tracked_objects::BirthOnThread& birth)
+BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth)
: location(birth.location()),
thread_name(birth.birth_thread()->thread_name()) {
}
@@ -238,9 +310,9 @@
// static
bool ThreadData::now_function_is_time_ = false;
-// A TLS slot which points to the ThreadData instance for the current thread. We
-// do a fake initialization here (zeroing out data), and then the real in-place
-// construction happens when we call tls_index_.Initialize().
+// A TLS slot which points to the ThreadData instance for the current thread.
+// We do a fake initialization here (zeroing out data), and then the real
+// in-place construction happens when we call tls_index_.Initialize().
// static
base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
@@ -288,7 +360,8 @@
PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
}
-ThreadData::~ThreadData() {}
+ThreadData::~ThreadData() {
+}
void ThreadData::PushToHeadOfList() {
// Toss in a hint of randomness (atop the uniniitalized value).
@@ -361,7 +434,7 @@
// static
void ThreadData::OnThreadTermination(void* thread_data) {
DCHECK(thread_data); // TLS should *never* call us with a NULL.
- // We must NOT do any allocations during this callback. There is a chance
+ // We must NOT do any allocations during this callback. There is a chance
// that the allocator is no longer active on this thread.
reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
}
@@ -385,9 +458,54 @@
}
// static
-void ThreadData::Snapshot(ProcessDataSnapshot* process_data_snapshot) {
- ThreadData::SnapshotCurrentPhase(
- &process_data_snapshot->phased_process_data_snapshots[0]);
+void ThreadData::Snapshot(int current_profiling_phase,
+ ProcessDataSnapshot* process_data_snapshot) {
+ // Get an unchanging copy of a ThreadData list.
+ ThreadData* my_list = ThreadData::first();
+
+ // Gather data serially.
+ // This hackish approach *can* get some slightly corrupt tallies, as we are
+ // grabbing values without the protection of a lock, but it has the advantage
+ // of working even with threads that don't have message loops. If a user
+ // sees any strangeness, they can always just run their stats gathering a
+ // second time.
+ BirthCountMap birth_counts;
+ for (ThreadData* thread_data = my_list; thread_data;
+ thread_data = thread_data->next()) {
+ thread_data->SnapshotExecutedTasks(current_profiling_phase,
+ &process_data_snapshot->phased_snapshots,
+ &birth_counts);
+ }
+
+ // Add births that are still active -- i.e. objects that have tallied a birth,
+ // but have not yet tallied a matching death, and hence must be either
+ // running, queued up, or being held in limbo for future posting.
+ auto* current_phase_tasks =
+ &process_data_snapshot->phased_snapshots[current_profiling_phase].tasks;
+ for (const auto& birth_count : birth_counts) {
+ if (birth_count.second > 0) {
+ current_phase_tasks->push_back(
+ TaskSnapshot(BirthOnThreadSnapshot(*birth_count.first),
+ DeathDataSnapshot(birth_count.second, 0, 0, 0, 0, 0, 0),
+ "Still_Alive"));
+ }
+ }
+}
+
+// static
+void ThreadData::OnProfilingPhaseCompleted(int profiling_phase) {
+ // Get an unchanging copy of a ThreadData list.
+ ThreadData* my_list = ThreadData::first();
+
+ // Add snapshots for all instances of death data in all threads serially.
+ // This hackish approach *can* get some slightly corrupt tallies, as we are
+ // grabbing values without the protection of a lock, but it has the advantage
+ // of working even with threads that don't have message loops. Any corruption
+ // shouldn't cause "cascading damage" to anything else (in later phases).
+ for (ThreadData* thread_data = my_list; thread_data;
+ thread_data = thread_data->next()) {
+ thread_data->OnProfilingPhaseCompletedOnThread(profiling_phase);
+ }
}
Births* ThreadData::TallyABirth(const Location& location) {
@@ -404,22 +522,10 @@
birth_map_[location] = child;
}
- if (kTrackParentChildLinks && status_ > PROFILING_ACTIVE &&
- !parent_stack_.empty()) {
- const Births* parent = parent_stack_.top();
- ParentChildPair pair(parent, child);
- if (parent_child_set_.find(pair) == parent_child_set_.end()) {
- // Lock since the map may get relocated now, and other threads sometimes
- // snapshot it (but they lock before copying it).
- base::AutoLock lock(map_lock_);
- parent_child_set_.insert(pair);
- }
- }
-
return child;
}
-void ThreadData::TallyADeath(const Births& birth,
+void ThreadData::TallyADeath(const Births& births,
int32 queue_duration,
const TaskStopwatch& stopwatch) {
int32 run_duration = stopwatch.RunDurationMs();
@@ -428,9 +534,9 @@
const uint32 kSomePrimeNumber = 2147483647;
random_number_ += queue_duration + run_duration + kSomePrimeNumber;
// An address is going to have some randomness to it as well ;-).
- random_number_ ^= static_cast<uint32>(&birth - reinterpret_cast<Births*>(0));
+ random_number_ ^= static_cast<uint32>(&births - reinterpret_cast<Births*>(0));
- // We don't have queue durations without OS timer. OS timer is automatically
+ // We don't have queue durations without OS timer. OS timer is automatically
// used for task-post-timing, so the use of an alternate timer implies all
// queue times are invalid, unless it was explicitly said that we can trust
// the alternate timer.
@@ -440,22 +546,15 @@
queue_duration = 0;
}
- DeathMap::iterator it = death_map_.find(&birth);
+ DeathMap::iterator it = death_map_.find(&births);
DeathData* death_data;
if (it != death_map_.end()) {
death_data = &it->second;
} else {
base::AutoLock lock(map_lock_); // Lock as the map may get relocated now.
- death_data = &death_map_[&birth];
+ death_data = &death_map_[&births];
} // Release lock ASAP.
death_data->RecordDeath(queue_duration, run_duration, random_number_);
-
- if (!kTrackParentChildLinks)
- return;
- if (!parent_stack_.empty()) { // We might get turned off.
- DCHECK_EQ(parent_stack_.top(), &birth);
- parent_stack_.pop();
- }
}
// static
@@ -475,8 +574,8 @@
// Even if we have been DEACTIVATED, we will process any pending births so
// that our data structures (which counted the outstanding births) remain
// consistent.
- const Births* birth = completed_task.birth_tally;
- if (!birth)
+ const Births* births = completed_task.birth_tally;
+ if (!births)
return;
ThreadData* current_thread_data = stopwatch.GetThreadData();
if (!current_thread_data)
@@ -485,7 +584,7 @@
// Watch out for a race where status_ is changing, and hence one or both
// of start_of_run or end_of_run is zero. In that case, we didn't bother to
// get a time value since we "weren't tracking" and we were trying to be
- // efficient by not calling for a genuine time value. For simplicity, we'll
+ // efficient by not calling for a genuine time value. For simplicity, we'll
// use a default zero duration when we can't calculate a true value.
TrackedTime start_of_run = stopwatch.StartTime();
int32 queue_duration = 0;
@@ -493,18 +592,18 @@
queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
.InMilliseconds();
}
- current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
+ current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
// static
void ThreadData::TallyRunOnWorkerThreadIfTracking(
- const Births* birth,
+ const Births* births,
const TrackedTime& time_posted,
const TaskStopwatch& stopwatch) {
// Even if we have been DEACTIVATED, we will process any pending births so
// that our data structures (which counted the outstanding births) remain
// consistent.
- if (!birth)
+ if (!births)
return;
// TODO(jar): Support the option to coalesce all worker-thread activity under
@@ -512,7 +611,7 @@
// reduce memory (making it provably bounded), but run incrementally slower
// (since we'll use locks on TallyABirth and TallyADeath). The good news is
// that the locks on TallyADeath will be *after* the worker thread has run,
- // and hence nothing will be waiting for the completion (... besides some
+ // and hence nothing will be waiting for the completion (... besides some
// other thread that might like to run). Also, the worker threads tasks are
// generally longer, and hence the cost of the lock may perchance be amortized
// over the long task's lifetime.
@@ -525,17 +624,17 @@
if (!start_of_run.is_null()) {
queue_duration = (start_of_run - time_posted).InMilliseconds();
}
- current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
+ current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
// static
void ThreadData::TallyRunInAScopedRegionIfTracking(
- const Births* birth,
+ const Births* births,
const TaskStopwatch& stopwatch) {
// Even if we have been DEACTIVATED, we will process any pending births so
// that our data structures (which counted the outstanding births) remain
// consistent.
- if (!birth)
+ if (!births)
return;
ThreadData* current_thread_data = stopwatch.GetThreadData();
@@ -543,93 +642,74 @@
return;
int32 queue_duration = 0;
- current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
-}
-
-// static
-void ThreadData::SnapshotAllExecutedTasks(
- ProcessDataPhaseSnapshot* process_data_phase,
- BirthCountMap* birth_counts) {
- // Get an unchanging copy of a ThreadData list.
- ThreadData* my_list = ThreadData::first();
-
- // Gather data serially.
- // This hackish approach *can* get some slighly corrupt tallies, as we are
- // grabbing values without the protection of a lock, but it has the advantage
- // of working even with threads that don't have message loops. If a user
- // sees any strangeness, they can always just run their stats gathering a
- // second time.
- for (ThreadData* thread_data = my_list;
- thread_data;
- thread_data = thread_data->next()) {
- thread_data->SnapshotExecutedTasks(process_data_phase, birth_counts);
- }
-}
-
-// static
-void ThreadData::SnapshotCurrentPhase(
- ProcessDataPhaseSnapshot* process_data_phase) {
- // Add births that have run to completion to |collected_data|.
- // |birth_counts| tracks the total number of births recorded at each location
- // for which we have not seen a death count.
- BirthCountMap birth_counts;
- ThreadData::SnapshotAllExecutedTasks(process_data_phase, &birth_counts);
-
- // Add births that are still active -- i.e. objects that have tallied a birth,
- // but have not yet tallied a matching death, and hence must be either
- // running, queued up, or being held in limbo for future posting.
- for (const auto& birth_count : birth_counts) {
- if (birth_count.second > 0) {
- process_data_phase->tasks.push_back(TaskSnapshot(
- *birth_count.first, DeathData(birth_count.second), "Still_Alive"));
- }
- }
+ current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
void ThreadData::SnapshotExecutedTasks(
- ProcessDataPhaseSnapshot* process_data_phase,
+ int current_profiling_phase,
+ PhasedProcessDataSnapshotMap* phased_snapshots,
BirthCountMap* birth_counts) {
// Get copy of data, so that the data will not change during the iterations
// and processing.
- ThreadData::BirthMap birth_map;
- ThreadData::DeathMap death_map;
- ThreadData::ParentChildSet parent_child_set;
- SnapshotMaps(&birth_map, &death_map, &parent_child_set);
-
- for (const auto& death : death_map) {
- process_data_phase->tasks.push_back(
- TaskSnapshot(*death.first, death.second, thread_name()));
- (*birth_counts)[death.first] -= death.first->birth_count();
- }
+ BirthMap birth_map;
+ DeathsSnapshot deaths;
+ SnapshotMaps(current_profiling_phase, &birth_map, &deaths);
for (const auto& birth : birth_map) {
(*birth_counts)[birth.second] += birth.second->birth_count();
}
- if (!kTrackParentChildLinks)
- return;
+ for (const auto& death : deaths) {
+ (*birth_counts)[death.first] -= death.first->birth_count();
- for (const auto& parent_child : parent_child_set) {
- process_data_phase->descendants.push_back(
- ParentChildPairSnapshot(parent_child));
+ // For the current death data, walk through all its snapshots, starting from
+ // the current one, then from the previous profiling phase etc., and for
+ // each snapshot calculate the delta between the snapshot and the previous
+ // phase, if any. Store the deltas in the result.
+ for (const DeathDataPhaseSnapshot* phase = &death.second; phase;
+ phase = phase->prev) {
+ const DeathDataSnapshot& death_data =
+ phase->prev ? phase->death_data.Delta(phase->prev->death_data)
+ : phase->death_data;
+
+ if (death_data.count > 0) {
+ (*phased_snapshots)[phase->profiling_phase].tasks.push_back(
+ TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data,
+ thread_name()));
+ }
+ }
}
}
// This may be called from another thread.
-void ThreadData::SnapshotMaps(BirthMap* birth_map,
- DeathMap* death_map,
- ParentChildSet* parent_child_set) {
+void ThreadData::SnapshotMaps(int profiling_phase,
+ BirthMap* birth_map,
+ DeathsSnapshot* deaths) {
base::AutoLock lock(map_lock_);
+
for (const auto& birth : birth_map_)
(*birth_map)[birth.first] = birth.second;
- for (const auto& death : death_map_)
- (*death_map)[death.first] = death.second;
- if (!kTrackParentChildLinks)
- return;
+ for (const auto& death : death_map_) {
+ deaths->push_back(std::make_pair(
+ death.first,
+ DeathDataPhaseSnapshot(profiling_phase, death.second.count(),
+ death.second.run_duration_sum(),
+ death.second.run_duration_max(),
+ death.second.run_duration_sample(),
+ death.second.queue_duration_sum(),
+ death.second.queue_duration_max(),
+ death.second.queue_duration_sample(),
+ death.second.last_phase_snapshot())));
+ }
+}
- for (const auto& parent_child : parent_child_set_)
- parent_child_set->insert(parent_child);
+void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) {
+ base::AutoLock lock(map_lock_);
+
+ for (auto& death : death_map_) {
+ death.second.OnProfilingPhaseCompleted(profiling_phase);
+ }
}
static void OptionallyInitializeAlternateTimer() {
@@ -674,13 +754,10 @@
// never again change in this process.
++incarnation_counter_;
- // The lock is not critical for setting status_, but it doesn't hurt. It also
+ // The lock is not critical for setting status_, but it doesn't hurt. It also
// ensures that if we have a racy initialization, that we'll bail as soon as
// we get the lock earlier in this method.
status_ = kInitialStartupState;
- if (!kTrackParentChildLinks &&
- kInitialStartupState == PROFILING_CHILDREN_ACTIVE)
- status_ = PROFILING_ACTIVE;
DCHECK(status_ != UNINITIALIZED);
return true;
}
@@ -688,12 +765,12 @@
// static
bool ThreadData::InitializeAndSetTrackingStatus(Status status) {
DCHECK_GE(status, DEACTIVATED);
- DCHECK_LE(status, PROFILING_CHILDREN_ACTIVE);
+ DCHECK_LE(status, PROFILING_ACTIVE);
if (!Initialize()) // No-op if already initialized.
return false; // Not compiled in.
- if (!kTrackParentChildLinks && status > DEACTIVATED)
+ if (status > DEACTIVATED)
status = PROFILING_ACTIVE;
status_ = status;
return true;
@@ -710,20 +787,6 @@
}
// static
-bool ThreadData::TrackingParentChildStatus() {
- return status_ >= PROFILING_CHILDREN_ACTIVE;
-}
-
-// static
-void ThreadData::PrepareForStartOfRun(const Births* parent) {
- if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) {
- ThreadData* current_thread_data = Get();
- if (current_thread_data)
- current_thread_data->parent_stack_.push(parent);
- }
-}
-
-// static
void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
DCHECK(now_function);
if (kAllowAlternateTimeSourceHandling)
@@ -909,11 +972,37 @@
}
//------------------------------------------------------------------------------
+// DeathDataPhaseSnapshot
+
+DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
+ int profiling_phase,
+ int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample,
+ const DeathDataPhaseSnapshot* prev)
+ : profiling_phase(profiling_phase),
+ death_data(count,
+ run_duration_sum,
+ run_duration_max,
+ run_duration_sample,
+ queue_duration_sum,
+ queue_duration_max,
+ queue_duration_sample),
+ prev(prev) {
+}
+
+//------------------------------------------------------------------------------
+// TaskSnapshot
+
TaskSnapshot::TaskSnapshot() {
}
-TaskSnapshot::TaskSnapshot(const BirthOnThread& birth,
- const DeathData& death_data,
+TaskSnapshot::TaskSnapshot(const BirthOnThreadSnapshot& birth,
+ const DeathDataSnapshot& death_data,
const std::string& death_thread_name)
: birth(birth),
death_data(death_data),
@@ -924,21 +1013,6 @@
}
//------------------------------------------------------------------------------
-// ParentChildPairSnapshot
-
-ParentChildPairSnapshot::ParentChildPairSnapshot() {
-}
-
-ParentChildPairSnapshot::ParentChildPairSnapshot(
- const ThreadData::ParentChildPair& parent_child)
- : parent(*parent_child.first),
- child(*parent_child.second) {
-}
-
-ParentChildPairSnapshot::~ParentChildPairSnapshot() {
-}
-
-//------------------------------------------------------------------------------
// ProcessDataPhaseSnapshot
ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() {
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 9643265..cd69fb7 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -22,6 +22,7 @@
#include "base/profiler/alternate_timer.h"
#include "base/profiler/tracked_time.h"
#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
#include "base/threading/thread_local_storage.h"
namespace base {
@@ -85,7 +86,7 @@
// threads there are, and how many Locations of construction there are.
// Fortunately, we don't use memory that is the product of those two counts, but
// rather we only need one Births instance for each thread that constructs an
-// instance at a Location. In many cases, instances are only created on one
+// instance at a Location. In many cases, instances are only created on one
// thread, so the memory utilization is actually fairly restrained.
//
// Lastly, when an instance is deleted, the final tallies of statistics are
@@ -106,14 +107,14 @@
// Each thread maintains a list of data items specific to that thread in a
// ThreadData instance (for that specific thread only). The two critical items
// are lists of DeathData and Births instances. These lists are maintained in
-// STL maps, which are indexed by Location. As noted earlier, we can compare
+// STL maps, which are indexed by Location. As noted earlier, we can compare
// locations very efficiently as we consider the underlying data (file,
// function, line) to be atoms, and hence pointer comparison is used rather than
// (slow) string comparisons.
//
// To provide a mechanism for iterating over all "known threads," which means
// threads that have recorded a birth or a death, we create a singly linked list
-// of ThreadData instances. Each such instance maintains a pointer to the next
+// of ThreadData instances. Each such instance maintains a pointer to the next
// one. A static member of ThreadData provides a pointer to the first item on
// this global list, and access via that all_thread_data_list_head_ item
// requires the use of the list_lock_.
@@ -148,14 +149,13 @@
// TaskSnapshot instances, so that such instances can be sorted and
// aggregated (and remain frozen during our processing).
//
-// Profiling consists of phases. The concrete phase in the sequence of phases is
-// identified by its 0-based index.
+// Profiling consists of phases. The concrete phase in the sequence of phases
+// is identified by its 0-based index.
//
// The ProcessDataPhaseSnapshot struct is a serialized representation of the
-// list of ThreadData objects for a process for a concrete profiling phase. It
-// holds a set of TaskSnapshots and tracks parent/child relationships for the
-// executed tasks. The statistics in a snapshot are gathered asynhcronously
-// relative to their ongoing updates.
+// list of ThreadData objects for a process for a concrete profiling phase. It
+// holds a set of TaskSnapshots. The statistics in a snapshot are gathered
+// asynhcronously relative to their ongoing updates.
// It is possible, though highly unlikely, that stats could be incorrectly
// recorded by this process (all data is held in 32 bit ints, but we are not
// atomically collecting all data, so we could have count that does not, for
@@ -177,13 +177,6 @@
// for upload via UMA (where correctness of data may be more significant than
// for a single screen of about:profiler).
//
-// TODO(jar): We should support (optionally) the recording of parent-child
-// relationships for tasks. This should be done by detecting what tasks are
-// Born during the running of a parent task. The resulting data can be used by
-// a smarter profiler to aggregate the cost of a series of child tasks into
-// the ancestor task. It can also be used to illuminate what child or parent is
-// related to each task.
-//
// TODO(jar): We need to store DataCollections, and provide facilities for
// taking the difference between two gathered DataCollections. For now, we're
// just adding a hack that Reset()s to zero all counts and stats. This is also
@@ -254,64 +247,29 @@
};
//------------------------------------------------------------------------------
-// Basic info summarizing multiple destructions of a tracked object with a
-// single birthplace (fixed Location). Used both on specific threads, and also
-// in snapshots when integrating assembled data.
-
-class BASE_EXPORT DeathData {
- public:
- // Default initializer.
- DeathData();
-
- // When deaths have not yet taken place, and we gather data from all the
- // threads, we create DeathData stats that tally the number of births without
- // a corresponding death.
- explicit DeathData(int count);
-
- // Update stats for a task destruction (death) that had a Run() time of
- // |duration|, and has had a queueing delay of |queue_duration|.
- void RecordDeath(const int32 queue_duration,
- const int32 run_duration,
- const uint32 random_number);
-
- // Metrics accessors, used only for serialization and in tests.
- int count() const;
- int32 run_duration_sum() const;
- int32 run_duration_max() const;
- int32 run_duration_sample() const;
- int32 queue_duration_sum() const;
- int32 queue_duration_max() const;
- int32 queue_duration_sample() const;
-
- // Reset all tallies to zero. This is used as a hack on realtime data.
- void Clear();
-
- private:
- // Members are ordered from most regularly read and updated, to least
- // frequently used. This might help a bit with cache lines.
- // Number of runs seen (divisor for calculating averages).
- int count_;
- // Basic tallies, used to compute averages.
- int32 run_duration_sum_;
- int32 queue_duration_sum_;
- // Max values, used by local visualization routines. These are often read,
- // but rarely updated.
- int32 run_duration_max_;
- int32 queue_duration_max_;
- // Samples, used by crowd sourcing gatherers. These are almost never read,
- // and rarely updated.
- int32 run_duration_sample_;
- int32 queue_duration_sample_;
-};
-
-//------------------------------------------------------------------------------
// A "snapshotted" representation of the DeathData class.
struct BASE_EXPORT DeathDataSnapshot {
DeathDataSnapshot();
- explicit DeathDataSnapshot(const DeathData& death_data);
+
+ // Constructs the snapshot from individual values.
+ // The alternative would be taking a DeathData parameter, but this would
+ // create a loop since DeathData indirectly refers DeathDataSnapshot. Passing
+ // a wrapper structure as a param or using an empty constructor for
+ // snapshotting DeathData would be less efficient.
+ DeathDataSnapshot(int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample);
~DeathDataSnapshot();
+ // Calculates and returns the delta between this snapshot and an earlier
+ // snapshot of the same task |older|.
+ DeathDataSnapshot Delta(const DeathDataSnapshot& older) const;
+
int count;
int32 run_duration_sum;
int32 run_duration_max;
@@ -322,6 +280,107 @@
};
//------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData for a particular profiling
+// phase. Used as an element of the list of phase snapshots owned by DeathData.
+
+struct DeathDataPhaseSnapshot {
+ DeathDataPhaseSnapshot(int profiling_phase,
+ int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample,
+ const DeathDataPhaseSnapshot* prev);
+
+ // Profiling phase at which completion this snapshot was taken.
+ int profiling_phase;
+
+ // Death data snapshot.
+ DeathDataSnapshot death_data;
+
+ // Pointer to a snapshot from the previous phase.
+ const DeathDataPhaseSnapshot* prev;
+};
+
+//------------------------------------------------------------------------------
+// Information about deaths of a task on a given thread, called "death thread".
+// Access to members of this class is never protected by a lock. The fields
+// are accessed in such a way that corruptions resulting from race conditions
+// are not significant, and don't accumulate as a result of multiple accesses.
+// All invocations of DeathData::OnProfilingPhaseCompleted and
+// ThreadData::SnapshotMaps (which takes DeathData snapshot) in a given process
+// must be called from the same thread. It doesn't matter what thread it is, but
+// it's important the same thread is used as a snapshot thread during the whole
+// process lifetime. All fields except sample_probability_count_ can be
+// snapshotted.
+
+class BASE_EXPORT DeathData {
+ public:
+ DeathData();
+ DeathData(const DeathData& other);
+ ~DeathData();
+
+ // Update stats for a task destruction (death) that had a Run() time of
+ // |duration|, and has had a queueing delay of |queue_duration|.
+ void RecordDeath(const int32 queue_duration,
+ const int32 run_duration,
+ const uint32 random_number);
+
+ // Metrics and past snapshots accessors, used only for serialization and in
+ // tests.
+ int count() const;
+ int32 run_duration_sum() const;
+ int32 run_duration_max() const;
+ int32 run_duration_sample() const;
+ int32 queue_duration_sum() const;
+ int32 queue_duration_max() const;
+ int32 queue_duration_sample() const;
+ const DeathDataPhaseSnapshot* last_phase_snapshot() const;
+
+ // Called when the current profiling phase, identified by |profiling_phase|,
+ // ends.
+ // Must be called only on the snapshot thread.
+ void OnProfilingPhaseCompleted(int profiling_phase);
+
+ private:
+ // Members are ordered from most regularly read and updated, to least
+ // frequently used. This might help a bit with cache lines.
+ // Number of runs seen (divisor for calculating averages).
+ // Can be incremented only on the death thread.
+ int count_;
+
+ // Count used in determining probability of selecting exec/queue times from a
+ // recorded death as samples.
+ // Gets incremented only on the death thread, but can be set to 0 by
+ // OnProfilingPhaseCompleted() on the snapshot thread.
+ int sample_probability_count_;
+
+ // Basic tallies, used to compute averages. Can be incremented only on the
+ // death thread.
+ int32 run_duration_sum_;
+ int32 queue_duration_sum_;
+ // Max values, used by local visualization routines. These are often read,
+ // but rarely updated. The max values get assigned only on the death thread,
+ // but these fields can be set to 0 by OnProfilingPhaseCompleted() on the
+ // snapshot thread.
+ int32 run_duration_max_;
+ int32 queue_duration_max_;
+ // Samples, used by crowd sourcing gatherers. These are almost never read,
+ // and rarely updated. They can be modified only on the death thread.
+ int32 run_duration_sample_;
+ int32 queue_duration_sample_;
+
+ // Snapshot of this death data made at the last profiling phase completion, if
+ // any. DeathData owns the whole list starting with this pointer.
+ // Can be accessed only on the snapshot thread.
+ const DeathDataPhaseSnapshot* last_phase_snapshot_;
+
+ DISALLOW_ASSIGN(DeathData);
+};
+
+//------------------------------------------------------------------------------
// A temporary collection of data that can be sorted and summarized. It is
// gathered (carefully) from many threads. Instances are held in arrays and
// processed, filtered, and rendered.
@@ -330,12 +389,14 @@
struct BASE_EXPORT TaskSnapshot {
TaskSnapshot();
- TaskSnapshot(const BirthOnThread& birth,
- const DeathData& death_data,
+ TaskSnapshot(const BirthOnThreadSnapshot& birth,
+ const DeathDataSnapshot& death_data,
const std::string& death_thread_name);
~TaskSnapshot();
BirthOnThreadSnapshot birth;
+ // Delta between death data for a thread for a certain profiling phase and the
+ // snapshot for the pervious phase, if any. Otherwise, just a snapshot.
DeathDataSnapshot death_data;
std::string death_thread_name;
};
@@ -361,19 +422,15 @@
// Current allowable states of the tracking system. The states can vary
// between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED.
enum Status {
- UNINITIALIZED, // PRistine, link-time state before running.
- DORMANT_DURING_TESTS, // Only used during testing.
- DEACTIVATED, // No longer recording profiling.
- PROFILING_ACTIVE, // Recording profiles (no parent-child links).
- PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links.
- STATUS_LAST = PROFILING_CHILDREN_ACTIVE
+ UNINITIALIZED, // Pristine, link-time state before running.
+ DORMANT_DURING_TESTS, // Only used during testing.
+ DEACTIVATED, // No longer recording profiling.
+ PROFILING_ACTIVE, // Recording profiles.
+ STATUS_LAST = PROFILING_ACTIVE
};
typedef base::hash_map<Location, Births*, Location::Hash> BirthMap;
typedef std::map<const Births*, DeathData> DeathMap;
- typedef std::pair<const Births*, const Births*> ParentChildPair;
- typedef std::set<ParentChildPair> ParentChildSet;
- typedef std::stack<const Births*> ParentStack;
// Initialize the current thread context with a new instance of ThreadData.
// This is used by all threads that have names, and should be explicitly
@@ -388,8 +445,21 @@
static ThreadData* Get();
// Fills |process_data_snapshot| with phased snapshots of all profiling
- // phases, including the current one.
- static void Snapshot(ProcessDataSnapshot* process_data_snapshot);
+ // phases, including the current one, identified by |current_profiling_phase|.
+ // |current_profiling_phase| is necessary because a child process can start
+ // after several phase-changing events, so it needs to receive the current
+ // phase number from the browser process to fill the correct entry for the
+ // current phase in the |process_data_snapshot| map.
+ static void Snapshot(int current_profiling_phase,
+ ProcessDataSnapshot* process_data_snapshot);
+
+ // Called when the current profiling phase, identified by |profiling_phase|,
+ // ends.
+ // |profiling_phase| is necessary because a child process can start after
+ // several phase-changing events, so it needs to receive the phase number from
+ // the browser process to fill the correct entry in the
+ // completed_phases_snapshots_ map.
+ static void OnProfilingPhaseCompleted(int profiling_phase);
// Finds (or creates) a place to count births from the given location in this
// thread, and increment that tally.
@@ -403,7 +473,7 @@
// delayed tasks, and it indicates when the task should have run (i.e., when
// it should have posted out of the timer queue, and into the work queue.
// The |end_of_run| was just obtained by a call to Now() (just after the task
- // finished). It is provided as an argument to help with testing.
+ // finished). It is provided as an argument to help with testing.
static void TallyRunOnNamedThreadIfTracking(
const base::TrackingInfo& completed_task,
const TaskStopwatch& stopwatch);
@@ -415,31 +485,25 @@
// the task.
// The |end_of_run| was just obtained by a call to Now() (just after the task
// finished).
- static void TallyRunOnWorkerThreadIfTracking(const Births* birth,
+ static void TallyRunOnWorkerThreadIfTracking(const Births* births,
const TrackedTime& time_posted,
const TaskStopwatch& stopwatch);
// Record the end of execution in region, generally corresponding to a scope
// being exited.
- static void TallyRunInAScopedRegionIfTracking(const Births* birth,
+ static void TallyRunInAScopedRegionIfTracking(const Births* births,
const TaskStopwatch& stopwatch);
const std::string& thread_name() const { return thread_name_; }
// Initializes all statics if needed (this initialization call should be made
- // while we are single threaded). Returns false if unable to initialize.
+ // while we are single threaded). Returns false if unable to initialize.
static bool Initialize();
// Sets internal status_.
// If |status| is false, then status_ is set to DEACTIVATED.
- // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or
- // PROFILING_CHILDREN_ACTIVE.
- // If tracking is not compiled in, this function will return false.
- // If parent-child tracking is not compiled in, then an attempt to set the
- // status to PROFILING_CHILDREN_ACTIVE will only result in a status of
- // PROFILING_ACTIVE (i.e., it can't be set to a higher level than what is
- // compiled into the binary, and parent-child tracking at the
- // PROFILING_CHILDREN_ACTIVE level might not be compiled in).
+ // If |status| is true, then status_ is set to PROFILING_ACTIVE.
+ // If it fails to initialize the TLS slot, this function will return false.
static bool InitializeAndSetTrackingStatus(Status status);
static Status status();
@@ -448,17 +512,6 @@
// DEACTIVATED).
static bool TrackingStatus();
- // For testing only, indicate if the status of parent-child tracking is turned
- // on. This is currently a compiled option, atop TrackingStatus().
- static bool TrackingParentChildStatus();
-
- // Marks a start of a tracked run. It's super fast when tracking is disabled,
- // and has some internal side effects when we are tracking, so that we can
- // deduce the amount of time accumulated outside of execution of tracked runs.
- // The task that will be tracked is passed in as |parent| so that parent-child
- // relationships can be (optionally) calculated.
- static void PrepareForStartOfRun(const Births* parent);
-
// Enables profiler timing.
static void EnableProfilerTiming();
@@ -489,10 +542,12 @@
friend class TrackedObjectsTest;
FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown);
FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown);
- FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest);
typedef std::map<const BirthOnThread*, int> BirthCountMap;
+ typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>>
+ DeathsSnapshot;
+
// Worker thread construction creates a name since there is none.
explicit ThreadData(int thread_number);
@@ -517,36 +572,31 @@
Births* TallyABirth(const Location& location);
// Find a place to record a death on this thread.
- void TallyADeath(const Births& birth,
+ void TallyADeath(const Births& births,
int32 queue_duration,
const TaskStopwatch& stopwatch);
- // Snapshot (under a lock) the profiled data for the tasks in each ThreadData
- // instance. Also updates the |birth_counts| tally for each task to keep
- // track of the number of living instances of the task.
- static void SnapshotAllExecutedTasks(
- ProcessDataPhaseSnapshot* process_data_phase,
- BirthCountMap* birth_counts);
-
- // Fills |process_data_phase| with all the recursive results in our process.
- static void SnapshotCurrentPhase(
- ProcessDataPhaseSnapshot* process_data_phase);
-
// Snapshots (under a lock) the profiled data for the tasks for this thread
- // and writes all of the executed tasks' data -- i.e. the data for the tasks
- // with with entries in the death_map_ -- into |process_data_phase|. Also
- // updates the |birth_counts| tally for each task to keep track of the number
- // of living instances of the task -- that is, each task maps to the number of
- // births for the task that have not yet been balanced by a death.
- void SnapshotExecutedTasks(ProcessDataPhaseSnapshot* process_data_phase,
+ // and writes all of the executed tasks' data -- i.e. the data for all
+ // profiling phases (including the current one: |current_profiling_phase|) for
+ // the tasks with with entries in the death_map_ -- into |phased_snapshots|.
+ // Also updates the |birth_counts| tally for each task to keep track of the
+ // number of living instances of the task -- that is, each task maps to the
+ // number of births for the task that have not yet been balanced by a death.
+ void SnapshotExecutedTasks(int current_profiling_phase,
+ PhasedProcessDataSnapshotMap* phased_snapshots,
BirthCountMap* birth_counts);
// Using our lock, make a copy of the specified maps. This call may be made
// on non-local threads, which necessitate the use of the lock to prevent
// the map(s) from being reallocated while they are copied.
- void SnapshotMaps(BirthMap* birth_map,
- DeathMap* death_map,
- ParentChildSet* parent_child_set);
+ void SnapshotMaps(int profiling_phase,
+ BirthMap* birth_map,
+ DeathsSnapshot* deaths);
+
+ // Called for this thread when the current profiling phase, identified by
+ // |profiling_phase|, ends.
+ void OnProfilingPhaseCompletedOnThread(int profiling_phase);
// This method is called by the TLS system when a thread terminates.
// The argument may be NULL if this thread has never tracked a birth or death.
@@ -578,7 +628,7 @@
// We use thread local store to identify which ThreadData to interact with.
static base::ThreadLocalStorage::StaticSlot tls_index_;
- // List of ThreadData instances for use with worker threads. When a worker
+ // List of ThreadData instances for use with worker threads. When a worker
// thread is done (terminated), we push it onto this list. When a new worker
// thread is created, we first try to re-use a ThreadData instance from the
// list, and if none are available, construct a new one.
@@ -595,7 +645,7 @@
static int worker_thread_data_creation_count_;
// The number of times TLS has called us back to cleanup a ThreadData
- // instance. This is only accessed while list_lock_ is held.
+ // instance. This is only accessed while list_lock_ is held.
static int cleanup_count_;
// Incarnation sequence number, indicating how many times (during unittests)
@@ -612,7 +662,7 @@
// We set status_ to SHUTDOWN when we shut down the tracking service.
static Status status_;
- // Link to next instance (null terminated list). Used to globally track all
+ // Link to next instance (null terminated list). Used to globally track all
// registered instances (corresponds to all registered threads where we keep
// data).
ThreadData* next_;
@@ -644,11 +694,6 @@
// locking before reading it.
DeathMap death_map_;
- // A set of parents that created children tasks on this thread. Each pair
- // corresponds to potentially non-local Births (location and thread), and a
- // local Births (that took place on this thread).
- ParentChildSet parent_child_set_;
-
// Lock to protect *some* access to BirthMap and DeathMap. The maps are
// regularly read and written on this thread, but may only be read from other
// threads. To support this, we acquire this lock if we are writing from this
@@ -657,16 +702,6 @@
// writing is only done from this thread.
mutable base::Lock map_lock_;
- // The stack of parents that are currently being profiled. This includes only
- // tasks that have started a timer recently via PrepareForStartOfRun(), but
- // not yet concluded with a NowForEndOfRun(). Usually this stack is one deep,
- // but if a scoped region is profiled, or <sigh> a task runs a nested-message
- // loop, then the stack can grow larger. Note that we don't try to deduct
- // time in nested profiles, as our current timer is based on wall-clock time,
- // and not CPU time (and we're hopeful that nested timing won't be a
- // significant additional cost).
- ParentStack parent_stack_;
-
// A random number that we used to select decide which sample to keep as a
// representative sample in each DeathData instance. We can't start off with
// much randomness (because we can't call RandInt() on all our threads), so
@@ -688,7 +723,7 @@
//------------------------------------------------------------------------------
// Stopwatch to measure task run time or simply create a time interval that will
-// be subtracted from the current most nested task's run time. Stopwatches
+// be subtracted from the current most nested task's run time. Stopwatches
// coordinate with the stopwatches in which they are nested to avoid
// double-counting nested tasks run times.
@@ -736,32 +771,17 @@
TaskStopwatch* parent_;
#if DCHECK_IS_ON()
- // State of the stopwatch. Stopwatch is first constructed in a created state
+ // State of the stopwatch. Stopwatch is first constructed in a created state
// state, then is optionally started/stopped, then destructed.
enum { CREATED, RUNNING, STOPPED } state_;
// Currently running stopwatch that is directly nested in this one, if such
- // stopwatch exists. NULL otherwise.
+ // stopwatch exists. NULL otherwise.
TaskStopwatch* child_;
#endif
};
//------------------------------------------------------------------------------
-// A snapshotted representation of a (parent, child) task pair, for tracking
-// hierarchical profiles.
-
-struct BASE_EXPORT ParentChildPairSnapshot {
- public:
- ParentChildPairSnapshot();
- explicit ParentChildPairSnapshot(
- const ThreadData::ParentChildPair& parent_child);
- ~ParentChildPairSnapshot();
-
- BirthOnThreadSnapshot parent;
- BirthOnThreadSnapshot child;
-};
-
-//------------------------------------------------------------------------------
// A snapshotted representation of the list of ThreadData objects for a process,
// for a single profiling phase.
@@ -771,7 +791,6 @@
~ProcessDataPhaseSnapshot();
std::vector<TaskSnapshot> tasks;
- std::vector<ParentChildPairSnapshot> descendants;
};
//------------------------------------------------------------------------------
@@ -783,7 +802,7 @@
ProcessDataSnapshot();
~ProcessDataSnapshot();
- PhasedProcessDataSnapshotMap phased_process_data_snapshots;
+ PhasedProcessDataSnapshotMap phased_snapshots;
base::ProcessId process_id;
};
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
index 5455fef..3537e54 100644
--- a/base/tracked_objects_unittest.cc
+++ b/base/tracked_objects_unittest.cc
@@ -71,9 +71,9 @@
int count,
int run_ms,
int queue_ms) {
- ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
- auto it = process_data.phased_process_data_snapshots.find(0);
- ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
const ProcessDataPhaseSnapshot& process_data_phase = it->second;
ASSERT_EQ(1u, process_data_phase.tasks.size());
@@ -101,8 +101,6 @@
EXPECT_EQ(death_thread, process_data_phase.tasks[0].death_thread_name);
- EXPECT_EQ(0u, process_data_phase.descendants.size());
-
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
@@ -122,7 +120,8 @@
TEST_F(TrackedObjectsTest, TaskStopwatchNoStartStop) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -134,7 +133,8 @@
TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
// Minimal test doesn't even create any tasks.
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -145,19 +145,17 @@
EXPECT_FALSE(data->next());
EXPECT_EQ(data, ThreadData::Get());
ThreadData::BirthMap birth_map;
- ThreadData::DeathMap death_map;
- ThreadData::ParentChildSet parent_child_set;
- data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+ ThreadData::DeathsSnapshot deaths;
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(0u, birth_map.size());
- EXPECT_EQ(0u, death_map.size());
- EXPECT_EQ(0u, parent_child_set.size());
+ EXPECT_EQ(0u, deaths.size());
// Clean up with no leaking.
Reset();
// Do it again, just to be sure we reset state completely.
- EXPECT_TRUE(ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE));
+ EXPECT_TRUE(
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE));
EXPECT_FALSE(ThreadData::first()); // No activity even on this thread.
data = ThreadData::Get();
EXPECT_TRUE(ThreadData::first()); // Now class was constructed.
@@ -165,42 +163,38 @@
EXPECT_FALSE(data->next());
EXPECT_EQ(data, ThreadData::Get());
birth_map.clear();
- death_map.clear();
- parent_child_set.clear();
- data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+ deaths.clear();
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(0u, birth_map.size());
- EXPECT_EQ(0u, death_map.size());
- EXPECT_EQ(0u, parent_child_set.size());
+ EXPECT_EQ(0u, deaths.size());
}
TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
// Instigate tracking on a single tracked object, on our thread.
const char kFunction[] = "TinyStartupShutdown";
Location location(kFunction, kFile, kLineNumber, NULL);
- Births* first_birth = ThreadData::TallyABirthIfActive(location);
+ ThreadData::TallyABirthIfActive(location);
ThreadData* data = ThreadData::first();
ASSERT_TRUE(data);
EXPECT_FALSE(data->next());
EXPECT_EQ(data, ThreadData::Get());
ThreadData::BirthMap birth_map;
- ThreadData::DeathMap death_map;
- ThreadData::ParentChildSet parent_child_set;
- data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+ ThreadData::DeathsSnapshot deaths;
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(1u, birth_map.size()); // 1 birth location.
EXPECT_EQ(1, birth_map.begin()->second->birth_count()); // 1 birth.
- EXPECT_EQ(0u, death_map.size()); // No deaths.
- EXPECT_EQ(0u, parent_child_set.size()); // No children.
+ EXPECT_EQ(0u, deaths.size()); // No deaths.
// Now instigate another birth, while we are timing the run of the first
// execution.
- ThreadData::PrepareForStartOfRun(first_birth);
// Create a child (using the same birth location).
// TrackingInfo will call TallyABirth() during construction.
const int32 start_time = 1;
@@ -218,30 +212,22 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
birth_map.clear();
- death_map.clear();
- parent_child_set.clear();
- data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+ deaths.clear();
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(1u, birth_map.size()); // 1 birth location.
EXPECT_EQ(2, birth_map.begin()->second->birth_count()); // 2 births.
- EXPECT_EQ(1u, death_map.size()); // 1 location.
- EXPECT_EQ(1, death_map.begin()->second.count()); // 1 death.
- if (ThreadData::TrackingParentChildStatus()) {
- EXPECT_EQ(1u, parent_child_set.size()); // 1 child.
- EXPECT_EQ(parent_child_set.begin()->first,
- parent_child_set.begin()->second);
- } else {
- EXPECT_EQ(0u, parent_child_set.size()); // no stats.
- }
+ EXPECT_EQ(1u, deaths.size()); // 1 location.
+ EXPECT_EQ(1, deaths.begin()->second.death_data.count); // 1 death.
// The births were at the same location as the one known death.
- EXPECT_EQ(birth_map.begin()->second, death_map.begin()->first);
+ EXPECT_EQ(birth_map.begin()->second, deaths.begin()->first);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
- ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
- auto it = process_data.phased_process_data_snapshots.find(0);
- ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
const ProcessDataPhaseSnapshot& process_data_phase = it->second;
ASSERT_EQ(1u, process_data_phase.tasks.size());
EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
@@ -261,43 +247,25 @@
EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_max);
EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sample);
EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].death_thread_name);
-
- if (ThreadData::TrackingParentChildStatus()) {
- ASSERT_EQ(1u, process_data_phase.descendants.size());
- EXPECT_EQ(kFile,
- process_data_phase.descendants[0].parent.location.file_name);
- EXPECT_EQ(kFunction,
- process_data_phase.descendants[0].parent.location.function_name);
- EXPECT_EQ(kLineNumber,
- process_data_phase.descendants[0].parent.location.line_number);
- EXPECT_EQ(kWorkerThreadName,
- process_data_phase.descendants[0].parent.thread_name);
- EXPECT_EQ(kFile,
- process_data_phase.descendants[0].child.location.file_name);
- EXPECT_EQ(kFunction,
- process_data_phase.descendants[0].child.location.function_name);
- EXPECT_EQ(kLineNumber,
- process_data_phase.descendants[0].child.location.line_number);
- EXPECT_EQ(kWorkerThreadName,
- process_data_phase.descendants[0].child.thread_name);
- } else {
- EXPECT_EQ(0u, process_data_phase.descendants.size());
- }
}
-TEST_F(TrackedObjectsTest, DeathDataTest) {
+TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
scoped_ptr<DeathData> data(new DeathData());
ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
EXPECT_EQ(data->run_duration_sum(), 0);
+ EXPECT_EQ(data->run_duration_max(), 0);
EXPECT_EQ(data->run_duration_sample(), 0);
EXPECT_EQ(data->queue_duration_sum(), 0);
+ EXPECT_EQ(data->queue_duration_max(), 0);
EXPECT_EQ(data->queue_duration_sample(), 0);
EXPECT_EQ(data->count(), 0);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot());
int32 run_ms = 42;
int32 queue_ms = 8;
@@ -305,31 +273,133 @@
const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
EXPECT_EQ(data->run_duration_sum(), run_ms);
+ EXPECT_EQ(data->run_duration_max(), run_ms);
EXPECT_EQ(data->run_duration_sample(), run_ms);
EXPECT_EQ(data->queue_duration_sum(), queue_ms);
+ EXPECT_EQ(data->queue_duration_max(), queue_ms);
EXPECT_EQ(data->queue_duration_sample(), queue_ms);
EXPECT_EQ(data->count(), 1);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot());
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+ EXPECT_EQ(data->run_duration_max(), run_ms);
EXPECT_EQ(data->run_duration_sample(), run_ms);
EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+ EXPECT_EQ(data->queue_duration_max(), queue_ms);
EXPECT_EQ(data->queue_duration_sample(), queue_ms);
EXPECT_EQ(data->count(), 2);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot());
+}
- DeathDataSnapshot snapshot(*data);
- EXPECT_EQ(2, snapshot.count);
- EXPECT_EQ(2 * run_ms, snapshot.run_duration_sum);
- EXPECT_EQ(run_ms, snapshot.run_duration_max);
- EXPECT_EQ(run_ms, snapshot.run_duration_sample);
- EXPECT_EQ(2 * queue_ms, snapshot.queue_duration_sum);
- EXPECT_EQ(queue_ms, snapshot.queue_duration_max);
- EXPECT_EQ(queue_ms, snapshot.queue_duration_sample);
+TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
+ if (!ThreadData::InitializeAndSetTrackingStatus(
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
+ return;
+ }
+
+ scoped_ptr<DeathData> data(new DeathData());
+ ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+
+ int32 run_ms = 42;
+ int32 queue_ms = 8;
+
+ const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
+ data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+ data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+
+ data->OnProfilingPhaseCompleted(123);
+ EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+ EXPECT_EQ(data->run_duration_max(), 0);
+ EXPECT_EQ(data->run_duration_sample(), run_ms);
+ EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+ EXPECT_EQ(data->queue_duration_max(), 0);
+ EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+ EXPECT_EQ(data->count(), 2);
+ ASSERT_NE(nullptr, data->last_phase_snapshot());
+ EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+ EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+ EXPECT_EQ(2 * run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sum);
+ EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+ EXPECT_EQ(run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sample);
+ EXPECT_EQ(2 * queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sum);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_max);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sample);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+
+ int32 run_ms1 = 21;
+ int32 queue_ms1 = 4;
+
+ data->RecordDeath(queue_ms1, run_ms1, kUnrandomInt);
+ EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms + run_ms1);
+ EXPECT_EQ(data->run_duration_max(), run_ms1);
+ EXPECT_EQ(data->run_duration_sample(), run_ms1);
+ EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms + queue_ms1);
+ EXPECT_EQ(data->queue_duration_max(), queue_ms1);
+ EXPECT_EQ(data->queue_duration_sample(), queue_ms1);
+ EXPECT_EQ(data->count(), 3);
+ ASSERT_NE(nullptr, data->last_phase_snapshot());
+ EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+ EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+ EXPECT_EQ(2 * run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sum);
+ EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+ EXPECT_EQ(run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sample);
+ EXPECT_EQ(2 * queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sum);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_max);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sample);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+}
+
+TEST_F(TrackedObjectsTest, Delta) {
+ if (!ThreadData::InitializeAndSetTrackingStatus(
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
+ return;
+ }
+
+ DeathDataSnapshot snapshot;
+ snapshot.count = 10;
+ snapshot.run_duration_sum = 100;
+ snapshot.run_duration_max = 50;
+ snapshot.run_duration_sample = 25;
+ snapshot.queue_duration_sum = 200;
+ snapshot.queue_duration_max = 101;
+ snapshot.queue_duration_sample = 26;
+
+ DeathDataSnapshot older_snapshot;
+ older_snapshot.count = 2;
+ older_snapshot.run_duration_sum = 95;
+ older_snapshot.run_duration_max = 48;
+ older_snapshot.run_duration_sample = 22;
+ older_snapshot.queue_duration_sum = 190;
+ older_snapshot.queue_duration_max = 99;
+ older_snapshot.queue_duration_sample = 21;
+
+ const DeathDataSnapshot& delta = snapshot.Delta(older_snapshot);
+ EXPECT_EQ(8, delta.count);
+ EXPECT_EQ(5, delta.run_duration_sum);
+ EXPECT_EQ(50, delta.run_duration_max);
+ EXPECT_EQ(25, delta.run_duration_sample);
+ EXPECT_EQ(10, delta.queue_duration_sum);
+ EXPECT_EQ(101, delta.queue_duration_max);
+ EXPECT_EQ(26, delta.queue_duration_sample);
}
TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotWorkerThread) {
// Start in the deactivated state.
if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -338,21 +408,23 @@
TallyABirth(location, std::string());
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
- ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
- auto it = process_data.phased_process_data_snapshots.find(0);
- ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
const ProcessDataPhaseSnapshot& process_data_phase = it->second;
- EXPECT_EQ(0u, process_data_phase.tasks.size());
- EXPECT_EQ(0u, process_data_phase.descendants.size());
+ ASSERT_EQ(0u, process_data_phase.tasks.size());
+
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotMainThread) {
// Start in the deactivated state.
if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -361,21 +433,23 @@
TallyABirth(location, kMainThreadName);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
- ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
- auto it = process_data.phased_process_data_snapshots.find(0);
- ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
const ProcessDataPhaseSnapshot& process_data_phase = it->second;
- EXPECT_EQ(0u, process_data_phase.tasks.size());
- EXPECT_EQ(0u, process_data_phase.descendants.size());
+ ASSERT_EQ(0u, process_data_phase.tasks.size());
+
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotWorkerThread) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -384,14 +458,15 @@
TallyABirth(location, std::string());
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
kStillAlive, 1, 0, 0);
}
TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotMainThread) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -400,14 +475,15 @@
TallyABirth(location, kMainThreadName);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName, kStillAlive,
1, 0, 0);
}
TEST_F(TrackedObjectsTest, LifeCycleToSnapshotMainThread) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -432,18 +508,395 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 1, 2, 4);
}
+TEST_F(TrackedObjectsTest, TwoPhases) {
+ if (!ThreadData::InitializeAndSetTrackingStatus(
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
+ return;
+ }
+
+ const char kFunction[] = "TwoPhases";
+ Location location(kFunction, kFile, kLineNumber, NULL);
+ TallyABirth(location, kMainThreadName);
+
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+ const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task(location, kDelayedStartTime);
+ pending_task.time_posted = kTimePosted; // Overwrite implied Now().
+
+ const unsigned int kStartOfRun = 5;
+ const unsigned int kEndOfRun = 7;
+ SetTestTime(kStartOfRun);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(kEndOfRun);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+ ThreadData::OnProfilingPhaseCompleted(0);
+
+ TallyABirth(location, kMainThreadName);
+
+ const TrackedTime kTimePosted1 = TrackedTime::FromMilliseconds(9);
+ const base::TimeTicks kDelayedStartTime1 = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task1(location, kDelayedStartTime1);
+ pending_task1.time_posted = kTimePosted1; // Overwrite implied Now().
+
+ const unsigned int kStartOfRun1 = 11;
+ const unsigned int kEndOfRun1 = 21;
+ SetTestTime(kStartOfRun1);
+ TaskStopwatch stopwatch1;
+ stopwatch1.Start();
+ SetTestTime(kEndOfRun1);
+ stopwatch1.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task1, stopwatch1);
+
+ ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(1, &process_data);
+
+ ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+ auto it0 = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+ ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase0.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase0.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase1.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase1.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+ EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, ThreePhases) {
+ if (!ThreadData::InitializeAndSetTrackingStatus(
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
+ return;
+ }
+
+ const char kFunction[] = "ThreePhases";
+ Location location(kFunction, kFile, kLineNumber, NULL);
+
+ // Phase 0
+ {
+ TallyABirth(location, kMainThreadName);
+
+ // TrackingInfo will call TallyABirth() during construction.
+ SetTestTime(10);
+ base::TrackingInfo pending_task(location, base::TimeTicks());
+
+ SetTestTime(17);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(23);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+ }
+
+ ThreadData::OnProfilingPhaseCompleted(0);
+
+ // Phase 1
+ {
+ TallyABirth(location, kMainThreadName);
+
+ SetTestTime(30);
+ base::TrackingInfo pending_task(location, base::TimeTicks());
+
+ SetTestTime(35);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(39);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+ }
+
+ ThreadData::OnProfilingPhaseCompleted(1);
+
+ // Phase 2
+ {
+ TallyABirth(location, kMainThreadName);
+
+ // TrackingInfo will call TallyABirth() during construction.
+ SetTestTime(40);
+ base::TrackingInfo pending_task(location, base::TimeTicks());
+
+ SetTestTime(43);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(45);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+ }
+
+ // Snapshot and check results.
+ ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(2, &process_data);
+
+ ASSERT_EQ(3u, process_data.phased_snapshots.size());
+
+ auto it0 = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+ ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase0.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase0.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+ EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase1.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase1.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+ auto it2 = process_data.phased_snapshots.find(2);
+ ASSERT_TRUE(it2 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase2 = it2->second;
+
+ ASSERT_EQ(1u, process_data_phase2.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase2.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase2.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase2.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase2.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].death_thread_name);
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesSecondEmpty) {
+ if (!ThreadData::InitializeAndSetTrackingStatus(
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
+ return;
+ }
+
+ const char kFunction[] = "TwoPhasesSecondEmpty";
+ Location location(kFunction, kFile, kLineNumber, NULL);
+ ThreadData::InitializeThreadContext(kMainThreadName);
+
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+ const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task(location, kDelayedStartTime);
+ pending_task.time_posted = kTimePosted; // Overwrite implied Now().
+
+ const unsigned int kStartOfRun = 5;
+ const unsigned int kEndOfRun = 7;
+ SetTestTime(kStartOfRun);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(kEndOfRun);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+ ThreadData::OnProfilingPhaseCompleted(0);
+
+ ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(1, &process_data);
+
+ ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+ auto it0 = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+ ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase0.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase0.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(0u, process_data_phase1.tasks.size());
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesFirstEmpty) {
+ if (!ThreadData::InitializeAndSetTrackingStatus(
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
+ return;
+ }
+
+ ThreadData::OnProfilingPhaseCompleted(0);
+
+ const char kFunction[] = "TwoPhasesSecondEmpty";
+ Location location(kFunction, kFile, kLineNumber, NULL);
+ ThreadData::InitializeThreadContext(kMainThreadName);
+
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+ const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task(location, kDelayedStartTime);
+ pending_task.time_posted = kTimePosted; // Overwrite implied Now().
+
+ const unsigned int kStartOfRun = 5;
+ const unsigned int kEndOfRun = 7;
+ SetTestTime(kStartOfRun);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(kEndOfRun);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+ ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(1, &process_data);
+
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase1.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase1.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
// We will deactivate tracking after the birth, and before the death, and
// demonstrate that the lifecycle is completely tallied. This ensures that
// our tallied births are matched by tallied deaths (except for when the
// task is still running, or is queued).
TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -472,7 +925,7 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 1, 2, 4);
}
@@ -482,6 +935,7 @@
TEST_F(TrackedObjectsTest, LifeCyclePreDeactivatedToSnapshotMainThread) {
// Start in the deactivated state.
if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -506,21 +960,23 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
- ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
- auto it = process_data.phased_process_data_snapshots.find(0);
- ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
const ProcessDataPhaseSnapshot& process_data_phase = it->second;
- EXPECT_EQ(0u, process_data_phase.tasks.size());
- EXPECT_EQ(0u, process_data_phase.descendants.size());
+ ASSERT_EQ(0u, process_data_phase.tasks.size());
+
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, TwoLives) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -556,14 +1012,15 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task2, stopwatch2);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 2, 2, 4);
}
TEST_F(TrackedObjectsTest, DifferentLives) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -596,11 +1053,11 @@
pending_task2.time_posted = kTimePosted; // Overwrite implied Now().
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
- ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
- auto it = process_data.phased_process_data_snapshots.find(0);
- ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
const ProcessDataPhaseSnapshot& process_data_phase = it->second;
ASSERT_EQ(2u, process_data_phase.tasks.size());
@@ -633,13 +1090,13 @@
EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_max);
EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sample);
EXPECT_EQ(kStillAlive, process_data_phase.tasks[1].death_thread_name);
- EXPECT_EQ(0u, process_data_phase.descendants.size());
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, TaskWithNestedExclusion) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -669,14 +1126,15 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 1, 6, 4);
}
TEST_F(TrackedObjectsTest, TaskWith2NestedExclusions) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -712,14 +1170,15 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 1, 13, 4);
}
TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+ ThreadData::PROFILING_ACTIVE)) {
+ // Don't run the test if task tracking is not compiled in.
return;
}
@@ -765,11 +1224,11 @@
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(&process_data);
+ ThreadData::Snapshot(0, &process_data);
- ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
- auto it = process_data.phased_process_data_snapshots.find(0);
- ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
const ProcessDataPhaseSnapshot& process_data_phase = it->second;
// The order in which the two task follow is platform-dependent.
@@ -808,7 +1267,6 @@
EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_max);
EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sample);
EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].death_thread_name);
- EXPECT_EQ(0u, process_data_phase.descendants.size());
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
diff --git a/base/vlog.cc b/base/vlog.cc
index 8612071..519ceff 100644
--- a/base/vlog.cc
+++ b/base/vlog.cc
@@ -50,7 +50,6 @@
: min_log_level_(min_log_level) {
DCHECK(min_log_level != NULL);
- typedef std::pair<std::string, std::string> KVPair;
int vlog_level = 0;
if (!v_switch.empty()) {
if (base::StringToInt(v_switch, &vlog_level)) {
@@ -60,13 +59,13 @@
}
}
- std::vector<KVPair> kv_pairs;
+ base::StringPairs kv_pairs;
if (!base::SplitStringIntoKeyValuePairs(
vmodule_switch, '=', ',', &kv_pairs)) {
DLOG(WARNING) << "Could not fully parse vmodule switch \""
<< vmodule_switch << "\"";
}
- for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
+ for (base::StringPairs::const_iterator it = kv_pairs.begin();
it != kv_pairs.end(); ++it) {
VmodulePattern pattern(it->first);
if (!base::StringToInt(it->second, &pattern.vlog_level)) {
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc
index 35609fc..5ebe185 100644
--- a/base/win/object_watcher.cc
+++ b/base/win/object_watcher.cc
@@ -92,7 +92,7 @@
// The destructor blocks on any callbacks that are in flight, so we know that
// that is always a pointer to a valid ObjectWater.
ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
- that->origin_loop_->PostTask(FROM_HERE, that->callback_);
+ that->origin_loop_->task_runner()->PostTask(FROM_HERE, that->callback_);
that->callback_.Reset();
}
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
index 19b381d..692b7b6 100644
--- a/base/win/pe_image.cc
+++ b/base/win/pe_image.cc
@@ -568,12 +568,11 @@
if (NULL == section_header)
return false;
-#pragma warning(suppress : 4302) // pointer truncation
- // These casts generate warnings because they are 32 bit specific.
// Don't follow the virtual RVAToAddr, use the one on the base.
- DWORD offset_within_section = reinterpret_cast<DWORD>(address) -
- reinterpret_cast<DWORD>(PEImage::RVAToAddr(
- section_header->VirtualAddress));
+ DWORD offset_within_section =
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(
+ PEImage::RVAToAddr(section_header->VirtualAddress)));
*on_disk_offset = section_header->PointerToRawData + offset_within_section;
return true;
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
index 9aead96..2452067 100644
--- a/base/win/scoped_hdc.h
+++ b/base/win/scoped_hdc.h
@@ -68,7 +68,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(CreateDCTraits);
};
-typedef GenericScopedHandle<CreateDCTraits, VerifierTraits> ScopedCreateDC;
+typedef GenericScopedHandle<CreateDCTraits, DummyVerifierTraits> ScopedCreateDC;
} // namespace win
} // namespace base
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc
index 284a6ef..d530d5b 100644
--- a/base/win/scoped_variant_unittest.cc
+++ b/base/win/scoped_variant_unittest.cc
@@ -27,34 +27,34 @@
FakeComObject() : ref_(0) {
}
- STDMETHOD_(DWORD, AddRef)() {
+ STDMETHOD_(DWORD, AddRef)() override {
ref_++;
return ref_;
}
- STDMETHOD_(DWORD, Release)() {
+ STDMETHOD_(DWORD, Release)() override {
ref_--;
return ref_;
}
- STDMETHOD(QueryInterface)(REFIID, void**) {
+ STDMETHOD(QueryInterface)(REFIID, void**) override { return E_NOTIMPL; }
+
+ STDMETHOD(GetTypeInfoCount)(UINT*) override { return E_NOTIMPL; }
+
+ STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; }
+
+ STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) override {
return E_NOTIMPL;
}
- STDMETHOD(GetTypeInfoCount)(UINT*) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(Invoke)(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*,
- EXCEPINFO*, UINT*) {
+ STDMETHOD(Invoke)(DISPID,
+ REFIID,
+ LCID,
+ WORD,
+ DISPPARAMS*,
+ VARIANT*,
+ EXCEPINFO*,
+ UINT*) override {
return E_NOTIMPL;
}
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
index 207fdbe..f8b2182 100644
--- a/base/win/shortcut.cc
+++ b/base/win/shortcut.cc
@@ -321,8 +321,8 @@
if (GetVersion() < VERSION_WIN7)
return false;
- int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarpin", shortcut,
- NULL, NULL, 0));
+ intptr_t result = reinterpret_cast<intptr_t>(
+ ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0));
return result > 32;
}
@@ -333,8 +333,8 @@
if (GetVersion() < VERSION_WIN7)
return false;
- int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin",
- shortcut, NULL, NULL, 0));
+ intptr_t result = reinterpret_cast<intptr_t>(
+ ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
return result > 32;
}
diff --git a/base/win/startup_information.h b/base/win/startup_information.h
index e7e21cb..73d9f3e 100644
--- a/base/win/startup_information.h
+++ b/base/win/startup_information.h
@@ -24,6 +24,8 @@
bool InitializeProcThreadAttributeList(DWORD attribute_count);
// Sets one entry in the initialized attribute list.
+ // |value| needs to live at least as long as the StartupInformation object
+ // this is called on.
bool UpdateProcThreadAttribute(DWORD_PTR attribute,
void* value,
size_t size);
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index 59ae375..c5b06c4 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -428,7 +428,7 @@
NULL,
NULL,
SW_SHOW);
- return reinterpret_cast<int>(ret) > 32;
+ return reinterpret_cast<intptr_t>(ret) > 32;
}
bool DismissVirtualKeyboard() {
diff --git a/build/all.gyp b/build/all.gyp
index 255a35c..1866c2e 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -124,6 +124,7 @@
'../jingle/jingle.gyp:*',
'../media/cast/cast.gyp:*',
'../media/media.gyp:*',
+ '../media/midi/midi.gyp:*',
'../mojo/mojo.gyp:*',
'../mojo/mojo_base.gyp:*',
'../ppapi/ppapi.gyp:*',
@@ -318,6 +319,7 @@
'../ui/base/ui_base_tests.gyp:ui_base_unittests',
'../ui/display/display.gyp:display_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../url/url.gyp:url_unittests',
],
'conditions': [
@@ -344,6 +346,7 @@
'../jingle/jingle.gyp:jingle_unittests',
'../media/cast/cast.gyp:cast_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../mojo/mojo.gyp:mojo',
'../ppapi/ppapi_internal.gyp:ppapi_unittests',
'../remoting/remoting.gyp:remoting_unittests',
@@ -567,6 +570,7 @@
'../content/content_shell_and_tests.gyp:content_shell',
'../gpu/gpu.gyp:gpu_perftests',
'../media/media.gyp:media_perftests',
+ '../media/midi/midi.gyp:midi_unittests',
'../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
'../tools/telemetry/telemetry.gyp:*',
],
@@ -681,6 +685,7 @@
'../content/content_shell_and_tests.gyp:content_browsertests',
'../content/content_shell_and_tests.gyp:content_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../third_party/webrtc/tools/tools.gyp:frame_analyzer',
'../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter',
],
@@ -814,6 +819,8 @@
'../ipc/ipc.gyp:ipc_tests',
'../media/media.gyp:media_perftests_apk',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests_apk',
+ '../media/midi/midi.gyp:midi_unittests',
'../net/net.gyp:net_unittests',
'../sandbox/sandbox.gyp:sandbox_linux_unittests_deps',
'../skia/skia_tests.gyp:skia_unittests',
@@ -843,6 +850,7 @@
'../gpu/gpu.gyp:gpu_unittests_apk',
'../ipc/ipc.gyp:ipc_tests_apk',
'../media/media.gyp:media_unittests_apk',
+ '../media/midi/midi.gyp:midi_unittests_apk',
'../net/net.gyp:net_unittests_apk',
'../sandbox/sandbox.gyp:sandbox_linux_jni_unittests_apk',
'../skia/skia_tests.gyp:skia_unittests_apk',
@@ -853,6 +861,7 @@
'../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
'../ui/events/events.gyp:events_unittests_apk',
'../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
+ '../ui/gl/gl_tests.gyp:gl_unittests_apk',
'../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests_apk',
],
'conditions': [
@@ -929,6 +938,7 @@
'../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
'../jingle/jingle.gyp:jingle_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../ppapi/ppapi_internal.gyp:ppapi_unittests',
'../printing/printing.gyp:printing_unittests',
'../remoting/remoting.gyp:remoting_unittests',
@@ -944,6 +954,7 @@
'../tools/telemetry/telemetry.gyp:*',
'../ui/base/ui_base_tests.gyp:ui_base_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../url/url.gyp:url_unittests',
],
},
@@ -968,6 +979,7 @@
'../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
'../jingle/jingle.gyp:jingle_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../ppapi/ppapi_internal.gyp:ppapi_unittests',
'../printing/printing.gyp:printing_unittests',
'../remoting/remoting.gyp:remoting_unittests',
@@ -982,6 +994,7 @@
'../tools/telemetry/telemetry.gyp:*',
'../ui/base/ui_base_tests.gyp:ui_base_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../url/url.gyp:url_unittests',
],
},
@@ -995,6 +1008,7 @@
'../ipc/ipc.gyp:ipc_tests',
'../jingle/jingle.gyp:jingle_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../net/net.gyp:net_unittests',
'../printing/printing.gyp:printing_unittests',
'../remoting/remoting.gyp:remoting_unittests',
@@ -1018,6 +1032,7 @@
'../ipc/ipc.gyp:ipc_tests',
'../jingle/jingle.gyp:jingle_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../net/net.gyp:net_unittests',
'../google_apis/gcm/gcm.gyp:gcm_unit_tests',
'../printing/printing.gyp:printing_unittests',
@@ -1031,6 +1046,7 @@
'../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
'../ui/base/ui_base_tests.gyp:ui_base_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../url/url.gyp:url_unittests',
],
},
@@ -1069,6 +1085,7 @@
'../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
'../jingle/jingle.gyp:jingle_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../ppapi/ppapi_internal.gyp:ppapi_unittests',
'../printing/printing.gyp:printing_unittests',
'../remoting/remoting.gyp:remoting_unittests',
@@ -1084,6 +1101,7 @@
'../ui/base/ui_base_tests.gyp:ui_base_unittests',
'../ui/events/events.gyp:events_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
'../ui/views/views.gyp:views_unittests',
'../url/url.gyp:url_unittests',
@@ -1108,6 +1126,7 @@
'../ipc/ipc.gyp:ipc_tests',
'../jingle/jingle.gyp:jingle_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../net/net.gyp:net_unittests',
'../printing/printing.gyp:printing_unittests',
'../remoting/remoting.gyp:remoting_unittests',
@@ -1166,6 +1185,7 @@
'../jingle/jingle.gyp:jingle_unittests',
'../media/cast/cast.gyp:cast_unittests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../mojo/mojo.gyp:mojo',
'../net/net.gyp:net_unittests',
'../printing/printing.gyp:printing_unittests',
@@ -1186,6 +1206,7 @@
'../ui/display/display.gyp:display_unittests',
'../ui/events/events.gyp:events_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../ui/keyboard/keyboard.gyp:keyboard_unittests',
'../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
'../url/url.gyp:url_unittests',
@@ -1234,12 +1255,14 @@
'../chrome/chrome.gyp:sync_integration_tests',
'../ipc/ipc.gyp:ipc_tests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../net/net.gyp:net_unittests_run',
'../printing/printing.gyp:printing_unittests',
'../sql/sql.gyp:sql_unittests',
'../sync/sync.gyp:sync_unit_tests',
'../ui/base/ui_base_tests.gyp:ui_base_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
'../ui/views/views.gyp:views_unittests',
'../url/url.gyp:url_unittests',
@@ -1273,6 +1296,7 @@
'../ui/display/display.gyp:display_unittests',
'../ui/events/events.gyp:*',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../ui/keyboard/keyboard.gyp:*',
'../ui/snapshot/snapshot.gyp:snapshot_unittests',
'../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 92095be..6e0a3de 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -42,6 +42,7 @@
input_api,
output_api,
unit_tests=[
+ J('pylib', 'base', 'test_dispatcher_unittest.py'),
J('pylib', 'device', 'battery_utils_test.py'),
J('pylib', 'device', 'device_utils_test.py'),
J('pylib', 'device', 'logcat_monitor_test.py'),
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
index 4e62332..778a8c2 100755
--- a/build/android/gyp/dex.py
+++ b/build/android/gyp/dex.py
@@ -15,7 +15,9 @@
def DoDex(options, paths):
dx_binary = os.path.join(options.android_sdk_tools, 'dx')
# See http://crbug.com/272064 for context on --force-jumbo.
- dex_cmd = [dx_binary, '--dex', '--force-jumbo', '--output', options.dex_path]
+ # --num-threads=10 made final dexing go from 10s -> 5s on a z620.
+ dex_cmd = [dx_binary, '--num-threads=10', '--dex', '--force-jumbo',
+ '--output', options.dex_path]
if options.no_locals != '0':
dex_cmd.append('--no-locals')
diff --git a/build/android/gyp/jinja_template.py b/build/android/gyp/jinja_template.py
index 6653f21..e7c9a34 100755
--- a/build/android/gyp/jinja_template.py
+++ b/build/android/gyp/jinja_template.py
@@ -51,7 +51,7 @@
os.path.abspath(inputs_base_dir))
if relpath.startswith(os.pardir):
raise Exception('input file %s is not contained in inputs base dir %s'
- % input_filename, inputs_base_dir)
+ % (input_filename, inputs_base_dir))
output_filename = os.path.join(temp_dir, relpath)
parent_dir = os.path.dirname(output_filename)
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py
index 1ca0338..2a7fdd3 100644
--- a/build/android/pylib/base/base_test_runner.py
+++ b/build/android/pylib/base/base_test_runner.py
@@ -26,14 +26,15 @@
class BaseTestRunner(object):
"""Base class for running tests on a single device."""
- def __init__(self, device_serial, tool):
+ def __init__(self, device, tool):
"""
Args:
- device: Tests will run on the device of this ID.
+ device: An instance of DeviceUtils that the tests will run on.
tool: Name of the Valgrind tool.
"""
- self.device_serial = device_serial
- self.device = device_utils.DeviceUtils(device_serial)
+ assert isinstance(device, device_utils.DeviceUtils)
+ self.device = device
+ self.device_serial = self.device.adb.GetDeviceSerial()
self.tool = CreateTool(tool, self.device)
self._http_server = None
self._forwarder_device_port = 8000
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
index 1a8e0c1..f919965 100644
--- a/build/android/pylib/base/test_dispatcher.py
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -21,7 +21,6 @@
import logging
import threading
-from pylib import android_commands
from pylib import constants
from pylib.base import base_test_result
from pylib.base import test_collection
@@ -102,7 +101,7 @@
for test in collection:
watcher.Reset()
try:
- if runner.device_serial not in android_commands.GetAttachedDevices():
+ if not runner.device.IsOnline():
# Device is unresponsive, stop handling tests on this device.
msg = 'Device %s is unresponsive.' % runner.device_serial
logging.warning(msg)
@@ -150,10 +149,7 @@
runner = runner_factory(device, index)
runner.SetUp()
out_runners.append(runner)
- except (device_errors.DeviceUnreachableError,
- # TODO(jbudorick) Remove this once the underlying implementations
- # for the above are switched or wrapped.
- android_commands.errors.DeviceUnresponsiveError) as e:
+ except device_errors.DeviceUnreachableError as e:
logging.warning('Failed to create shard for %s: [%s]', device, e)
@@ -195,10 +191,7 @@
# Catch DeviceUnreachableErrors and set a warning exit code
try:
workers.JoinAll(watcher)
- except (device_errors.DeviceUnreachableError,
- # TODO(jbudorick) Remove this once the underlying implementations
- # for the above are switched or wrapped.
- android_commands.errors.DeviceUnresponsiveError) as e:
+ except device_errors.DeviceUnreachableError as e:
logging.error(e)
if not all((len(tc) == 0 for tc in test_collections)):
@@ -236,7 +229,7 @@
threads = reraiser_thread.ReraiserThreadGroup(
[reraiser_thread.ReraiserThread(_SetUp,
[runner_factory, d, runners, counter],
- name=d[-4:])
+ name=str(d)[-4:])
for d in devices])
threads.StartAll()
threads.JoinAll(watchdog_timer.WatchdogTimer(timeout))
@@ -333,10 +326,7 @@
finally:
try:
_TearDownRunners(runners, setup_timeout)
- except (device_errors.DeviceUnreachableError,
- # TODO(jbudorick) Remove this once the underlying implementations
- # for the above are switched or wrapped.
- android_commands.errors.DeviceUnresponsiveError) as e:
+ except device_errors.DeviceUnreachableError as e:
logging.warning('Device unresponsive during TearDown: [%s]', e)
except Exception as e:
logging.error('Unexpected exception caught during TearDown: %s' % str(e))
diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
old mode 100644
new mode 100755
index b57cca9..cace9a6
--- a/build/android/pylib/base/test_dispatcher_unittest.py
+++ b/build/android/pylib/base/test_dispatcher_unittest.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# Copyright 2013 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.
@@ -10,27 +11,38 @@
import sys
import unittest
-sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),
- os.pardir, os.pardir))
-# Mock out android_commands.GetAttachedDevices().
-from pylib import android_commands
-android_commands.GetAttachedDevices = lambda: ['0', '1']
from pylib import constants
from pylib.base import base_test_result
from pylib.base import test_collection
from pylib.base import test_dispatcher
+from pylib.device import adb_wrapper
+from pylib.device import device_utils
from pylib.utils import watchdog_timer
+sys.path.append(
+ os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock
+
class TestException(Exception):
pass
+def _MockDevice(serial):
+ d = mock.MagicMock(spec=device_utils.DeviceUtils)
+ d.__str__.return_value = serial
+ d.adb = mock.MagicMock(spec=adb_wrapper.AdbWrapper)
+ d.adb.GetDeviceSerial = mock.MagicMock(return_value=serial)
+ d.IsOnline = mock.MagicMock(return_value=True)
+ return d
+
+
class MockRunner(object):
"""A mock TestRunner."""
- def __init__(self, device='0', shard_index=0):
- self.device_serial = device
+ def __init__(self, device=None, shard_index=0):
+ self.device = device or _MockDevice('0')
+ self.device_serial = self.device.adb.GetDeviceSerial()
self.shard_index = shard_index
self.setups = 0
self.teardowns = 0
@@ -57,7 +69,7 @@
class MockRunnerFailTwice(MockRunner):
- def __init__(self, device='0', shard_index=0):
+ def __init__(self, device=None, shard_index=0):
super(MockRunnerFailTwice, self).__init__(device, shard_index)
self._fails = 0
@@ -111,7 +123,7 @@
def testSetUp(self):
runners = []
counter = test_dispatcher._ThreadSafeCounter()
- test_dispatcher._SetUp(MockRunner, '0', runners, counter)
+ test_dispatcher._SetUp(MockRunner, _MockDevice('0'), runners, counter)
self.assertEqual(len(runners), 1)
self.assertEqual(runners[0].setups, 1)
@@ -135,7 +147,8 @@
self.test_collection_factory = lambda: shared_test_collection
def testCreate(self):
- runners = test_dispatcher._CreateRunners(MockRunner, ['0', '1'])
+ runners = test_dispatcher._CreateRunners(
+ MockRunner, [_MockDevice('0'), _MockDevice('1')])
for runner in runners:
self.assertEqual(runner.setups, 1)
self.assertEqual(set([r.device_serial for r in runners]),
@@ -144,27 +157,29 @@
set([0, 1]))
def testRun(self):
- runners = [MockRunner('0'), MockRunner('1')]
+ runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
results, exit_code = test_dispatcher._RunAllTests(
runners, self.test_collection_factory, 0)
self.assertEqual(len(results.GetPass()), len(self.tests))
self.assertEqual(exit_code, 0)
def testTearDown(self):
- runners = [MockRunner('0'), MockRunner('1')]
+ runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
test_dispatcher._TearDownRunners(runners)
for runner in runners:
self.assertEqual(runner.teardowns, 1)
def testRetry(self):
- runners = test_dispatcher._CreateRunners(MockRunnerFail, ['0', '1'])
+ runners = test_dispatcher._CreateRunners(
+ MockRunnerFail, [_MockDevice('0'), _MockDevice('1')])
results, exit_code = test_dispatcher._RunAllTests(
runners, self.test_collection_factory, 0)
self.assertEqual(len(results.GetFail()), len(self.tests))
self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
def testReraise(self):
- runners = test_dispatcher._CreateRunners(MockRunnerException, ['0', '1'])
+ runners = test_dispatcher._CreateRunners(
+ MockRunnerException, [_MockDevice('0'), _MockDevice('1')])
with self.assertRaises(TestException):
test_dispatcher._RunAllTests(runners, self.test_collection_factory, 0)
@@ -174,7 +189,8 @@
@staticmethod
def _RunShard(runner_factory):
return test_dispatcher.RunTests(
- ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=True)
+ ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
+ shard=True)
def testShard(self):
results, exit_code = TestShard._RunShard(MockRunner)
@@ -189,7 +205,7 @@
def testNoTests(self):
results, exit_code = test_dispatcher.RunTests(
- [], MockRunner, ['0', '1'], shard=True)
+ [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=True)
self.assertEqual(len(results.GetAll()), 0)
self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
@@ -199,7 +215,8 @@
@staticmethod
def _RunReplicate(runner_factory):
return test_dispatcher.RunTests(
- ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=False)
+ ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
+ shard=False)
def testReplicate(self):
results, exit_code = TestReplicate._RunReplicate(MockRunner)
@@ -215,7 +232,7 @@
def testNoTests(self):
results, exit_code = test_dispatcher.RunTests(
- [], MockRunner, ['0', '1'], shard=False)
+ [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=False)
self.assertEqual(len(results.GetAll()), 0)
self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index 6e92f6d..025860c 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -102,7 +102,7 @@
'org.chromium.android_webview.test'),
'gtest': PackageInfo(
'org.chromium.native_test',
- 'org.chromium.native_test.ChromeNativeTestActivity',
+ 'org.chromium.native_test.NativeTestActivity',
'/data/local/tmp/chrome-native-tests-command-line',
None,
None),
@@ -229,7 +229,8 @@
try:
return os.environ['BUILDTYPE']
except KeyError:
- raise Exception('The BUILDTYPE environment variable has not been set')
+ raise EnvironmentError(
+ 'The BUILDTYPE environment variable has not been set')
def SetBuildType(build_type):
@@ -240,7 +241,7 @@
os.environ['CHROMIUM_OUT_DIR'] = build_directory
-def SetOutputDirectort(output_directory):
+def SetOutputDirectory(output_directory):
os.environ['CHROMIUM_OUTPUT_DIR'] = output_directory
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index 20787c1..8e8abf8 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -450,7 +450,7 @@
timeout: (optional) Timeout per try in seconds.
retries: (optional) Number of retries to attempt.
"""
- cmd = ['backup', path]
+ cmd = ['backup', '-f', path]
if apk:
cmd.append('-apk')
if shared:
@@ -542,6 +542,24 @@
raise device_errors.AdbCommandFailedError(
['root'], output, device_serial=self._device_serial)
+ def Emu(self, cmd, timeout=_DEFAULT_TIMEOUT,
+ retries=_DEFAULT_RETRIES):
+ """Runs an emulator console command.
+
+ See http://developer.android.com/tools/devices/emulator.html#console
+
+ Args:
+ cmd: The command to run on the emulator console.
+ timeout: (optional) Timeout per try in seconds.
+ retries: (optional) Number of retries to attempt.
+
+ Returns:
+ The output of the emulator console command.
+ """
+ if isinstance(cmd, basestring):
+ cmd = [cmd]
+ return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries)
+
@property
def is_emulator(self):
return _EMULATOR_RE.match(self._device_serial)
diff --git a/build/android/pylib/device/battery_utils_test.py b/build/android/pylib/device/battery_utils_test.py
index 15b4c34..434b9d8 100755
--- a/build/android/pylib/device/battery_utils_test.py
+++ b/build/android/pylib/device/battery_utils_test.py
@@ -14,7 +14,6 @@
import sys
import unittest
-from pylib import android_commands
from pylib import constants
from pylib.device import battery_utils
from pylib.device import device_errors
@@ -62,8 +61,7 @@
def testInitWithDeviceUtil(self):
serial = '0fedcba987654321'
- a = android_commands.AndroidCommands(device=serial)
- d = device_utils.DeviceUtils(a)
+ d = device_utils.DeviceUtils(serial)
b = battery_utils.BatteryUtils(d)
self.assertEqual(d, b._device)
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 46aec6f..091bb8e 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -175,6 +175,29 @@
assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
+ def __eq__(self, other):
+ """Checks whether |other| refers to the same device as |self|.
+
+ Args:
+ other: The object to compare to. This can be a basestring, an instance
+ of adb_wrapper.AdbWrapper, or an instance of DeviceUtils.
+ Returns:
+ Whether |other| refers to the same device as |self|.
+ """
+ return self.adb.GetDeviceSerial() == str(other)
+
+ def __lt__(self, other):
+ """Compares two instances of DeviceUtils.
+
+ This merely compares their serial numbers.
+
+ Args:
+ other: The instance of DeviceUtils to compare to.
+ Returns:
+ Whether |self| is less than |other|.
+ """
+ return self.adb.GetDeviceSerial() < other.adb.GetDeviceSerial()
+
def __str__(self):
"""Returns the device serial."""
return self.adb.GetDeviceSerial()
@@ -535,9 +558,9 @@
with device_temp_file.DeviceTempFile(self.adb) as large_output_file:
cmd = '%s > %s' % (cmd, large_output_file.name)
logging.info('Large output mode enabled. Will write output to device '
- ' and read results from file.')
+ 'and read results from file.')
handle_large_command(cmd)
- return self.ReadFile(large_output_file.name)
+ return self.ReadFile(large_output_file.name, force_pull=True)
else:
try:
return handle_large_command(cmd)
@@ -853,13 +876,17 @@
if not real_device_path:
return [(host_path, device_path)]
- host_checksums = md5sum.CalculateHostMd5Sums([real_host_path])
- device_paths_to_md5 = (
- real_device_path if os.path.isfile(real_host_path)
- else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path))
- for p in host_checksums.iterkeys()))
- device_checksums = md5sum.CalculateDeviceMd5Sums(
- device_paths_to_md5, self)
+ try:
+ host_checksums = md5sum.CalculateHostMd5Sums([real_host_path])
+ device_paths_to_md5 = (
+ real_device_path if os.path.isfile(real_host_path)
+ else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path))
+ for p in host_checksums.iterkeys()))
+ device_checksums = md5sum.CalculateDeviceMd5Sums(
+ device_paths_to_md5, self)
+ except EnvironmentError as e:
+ logging.warning('Error calculating md5: %s', e)
+ return [(host_path, device_path)]
if os.path.isfile(host_path):
host_checksum = host_checksums.get(real_host_path)
@@ -1016,7 +1043,7 @@
+ r'(?P<date>\S+) +(?P<time>\S+) +(?P<name>.+)$')
@decorators.WithTimeoutAndRetriesFromInstance()
- def ReadFile(self, device_path, as_root=False,
+ def ReadFile(self, device_path, as_root=False, force_pull=False,
timeout=None, retries=None):
"""Reads the contents of a file from the device.
@@ -1025,6 +1052,9 @@
from the device.
as_root: A boolean indicating whether the read should be executed with
root privileges.
+ force_pull: A boolean indicating whether to force the operation to be
+ performed by pulling a file from the device. The default is, when the
+ contents are short, to retrieve the contents using cat instead.
timeout: timeout in seconds
retries: number of retries
@@ -1038,20 +1068,20 @@
CommandTimeoutError on timeout.
DeviceUnreachableError on missing device.
"""
- # TODO(jbudorick): Implement a generic version of Stat() that handles
- # as_root=True, then switch this implementation to use that.
- size = None
- ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root,
- check_return=True)
- for line in ls_out:
- m = self._LS_RE.match(line)
- if m and m.group('name') == posixpath.basename(device_path):
- size = int(m.group('size'))
- break
- else:
+ def get_size(path):
+ # TODO(jbudorick): Implement a generic version of Stat() that handles
+ # as_root=True, then switch this implementation to use that.
+ ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root,
+ check_return=True)
+ for line in ls_out:
+ m = self._LS_RE.match(line)
+ if m and m.group('name') == posixpath.basename(device_path):
+ return int(m.group('size'))
logging.warning('Could not determine size of %s.', device_path)
+ return None
- if 0 < size <= self._MAX_ADB_OUTPUT_LENGTH:
+ if (not force_pull
+ and 0 < get_size(device_path) <= self._MAX_ADB_OUTPUT_LENGTH):
return _JoinLines(self.RunShellCommand(
['cat', device_path], as_root=as_root, check_return=True))
elif as_root and self.NeedsSU():
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 4301e9d..e5e3936 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -161,6 +161,73 @@
msg, str(self.device)))
+class DeviceUtilsEqTest(DeviceUtilsTest):
+
+ def testEq_equal_deviceUtils(self):
+ other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
+ self.assertTrue(self.device == other)
+ self.assertTrue(other == self.device)
+
+ def testEq_equal_adbWrapper(self):
+ other = adb_wrapper.AdbWrapper('0123456789abcdef')
+ self.assertTrue(self.device == other)
+ self.assertTrue(other == self.device)
+
+ def testEq_equal_string(self):
+ other = '0123456789abcdef'
+ self.assertTrue(self.device == other)
+ self.assertTrue(other == self.device)
+
+ def testEq_devicesNotEqual(self):
+ other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdee'))
+ self.assertFalse(self.device == other)
+ self.assertFalse(other == self.device)
+
+ def testEq_identity(self):
+ self.assertTrue(self.device == self.device)
+
+ def testEq_serialInList(self):
+ devices = [self.device]
+ self.assertTrue('0123456789abcdef' in devices)
+
+
+class DeviceUtilsLtTest(DeviceUtilsTest):
+
+ def testLt_lessThan(self):
+ other = device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff'))
+ self.assertTrue(self.device < other)
+ self.assertTrue(other > self.device)
+
+ def testLt_greaterThan_lhs(self):
+ other = device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000'))
+ self.assertFalse(self.device < other)
+ self.assertFalse(other > self.device)
+
+ def testLt_equal(self):
+ other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
+ self.assertFalse(self.device < other)
+ self.assertFalse(other > self.device)
+
+ def testLt_sorted(self):
+ devices = [
+ device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')),
+ device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')),
+ ]
+ sorted_devices = sorted(devices)
+ self.assertEquals('0000000000000000',
+ sorted_devices[0].adb.GetDeviceSerial())
+ self.assertEquals('ffffffffffffffff',
+ sorted_devices[1].adb.GetDeviceSerial())
+
+
+class DeviceUtilsStrTest(DeviceUtilsTest):
+
+ def testStr_returnsSerial(self):
+ with self.assertCalls(
+ (self.call.adb.GetDeviceSerial(), '0123456789abcdef')):
+ self.assertEqual('0123456789abcdef', str(self.device))
+
+
class DeviceUtilsIsOnlineTest(DeviceUtilsTest):
def testIsOnline_true(self):
@@ -594,7 +661,8 @@
(mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
temp_file),
(self.call.adb.Shell(cmd_redirect)),
- (self.call.device.ReadFile(temp_file.name), 'something')):
+ (self.call.device.ReadFile(temp_file.name, force_pull=True),
+ 'something')):
self.assertEquals(
['something'],
self.device.RunShellCommand(
@@ -615,7 +683,8 @@
(mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
temp_file),
(self.call.adb.Shell(cmd_redirect)),
- (self.call.device.ReadFile(mock.ANY), 'something')):
+ (self.call.device.ReadFile(mock.ANY, force_pull=True),
+ 'something')):
self.assertEquals(['something'],
self.device.RunShellCommand(cmd, check_return=True))
@@ -1223,6 +1292,15 @@
self.device.ReadFile('/this/big/file/can.be.read.with.su',
as_root=True))
+ def testReadFile_forcePull(self):
+ contents = 'a' * 123456
+ with self.assertCall(
+ self.call.device._ReadFileWithPull('/read/this/big/test/file'),
+ contents):
+ self.assertEqual(
+ contents,
+ self.device.ReadFile('/read/this/big/test/file', force_pull=True))
+
class DeviceUtilsWriteFileTest(DeviceUtilsTest):
@@ -1539,14 +1617,6 @@
self.device.GetMemoryUsageForPid(4321))
-class DeviceUtilsStrTest(DeviceUtilsTest):
-
- def testStr_returnsSerial(self):
- with self.assertCalls(
- (self.call.adb.GetDeviceSerial(), '0123456789abcdef')):
- self.assertEqual('0123456789abcdef', str(self.device))
-
-
class DeviceUtilsClientCache(DeviceUtilsTest):
def testClientCache_twoCaches(self):
diff --git a/build/android/pylib/device/shared_prefs.py b/build/android/pylib/device/shared_prefs.py
new file mode 100644
index 0000000..32cef4b
--- /dev/null
+++ b/build/android/pylib/device/shared_prefs.py
@@ -0,0 +1,391 @@
+# Copyright 2015 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.
+
+"""Helper object to read and modify Shared Preferences from Android apps.
+
+See e.g.:
+ http://developer.android.com/reference/android/content/SharedPreferences.html
+"""
+
+import collections
+import logging
+import posixpath
+
+from xml.etree import ElementTree
+
+
+_XML_DECLARATION = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+
+
+class BasePref(object):
+ """Base class for getting/setting the value of a specific preference type.
+
+ Should not be instantiated directly. The SharedPrefs collection will
+ instantiate the appropriate subclasses, which directly manipulate the
+ underlying xml document, to parse and serialize values according to their
+ type.
+
+ Args:
+ elem: An xml ElementTree object holding the preference data.
+
+ Properties:
+ tag_name: A string with the tag that must be used for this preference type.
+ """
+ tag_name = None
+
+ def __init__(self, elem):
+ if elem.tag != type(self).tag_name:
+ raise TypeError('Property %r has type %r, but trying to access as %r' %
+ (elem.get('name'), elem.tag, type(self).tag_name))
+ self._elem = elem
+
+ def __str__(self):
+ """Get the underlying xml element as a string."""
+ return ElementTree.tostring(self._elem)
+
+ def get(self):
+ """Get the value of this preference."""
+ return self._elem.get('value')
+
+ def set(self, value):
+ """Set from a value casted as a string."""
+ self._elem.set('value', str(value))
+
+ @property
+ def has_value(self):
+ """Check whether the element has a value."""
+ return self._elem.get('value') is not None
+
+
+class BooleanPref(BasePref):
+ """Class for getting/setting a preference with a boolean value.
+
+ The underlying xml element has the form, e.g.:
+ <boolean name="featureEnabled" value="false" />
+ """
+ tag_name = 'boolean'
+ VALUES = {'true': True, 'false': False}
+
+ def get(self):
+ """Get the value as a Python bool."""
+ return type(self).VALUES[super(BooleanPref, self).get()]
+
+ def set(self, value):
+ """Set from a value casted as a bool."""
+ super(BooleanPref, self).set('true' if value else 'false')
+
+
+class FloatPref(BasePref):
+ """Class for getting/setting a preference with a float value.
+
+ The underlying xml element has the form, e.g.:
+ <float name="someMetric" value="4.7" />
+ """
+ tag_name = 'float'
+
+ def get(self):
+ """Get the value as a Python float."""
+ return float(super(FloatPref, self).get())
+
+
+class IntPref(BasePref):
+ """Class for getting/setting a preference with an int value.
+
+ The underlying xml element has the form, e.g.:
+ <int name="aCounter" value="1234" />
+ """
+ tag_name = 'int'
+
+ def get(self):
+ """Get the value as a Python int."""
+ return int(super(IntPref, self).get())
+
+
+class LongPref(IntPref):
+ """Class for getting/setting a preference with a long value.
+
+ The underlying xml element has the form, e.g.:
+ <long name="aLongCounter" value="1234" />
+
+ We use the same implementation from IntPref.
+ """
+ tag_name = 'long'
+
+
+class StringPref(BasePref):
+ """Class for getting/setting a preference with a string value.
+
+ The underlying xml element has the form, e.g.:
+ <string name="someHashValue">249b3e5af13d4db2</string>
+ """
+ tag_name = 'string'
+
+ def get(self):
+ """Get the value as a Python string."""
+ return self._elem.text
+
+ def set(self, value):
+ """Set from a value casted as a string."""
+ self._elem.text = str(value)
+
+
+class StringSetPref(StringPref):
+ """Class for getting/setting a preference with a set of string values.
+
+ The underlying xml element has the form, e.g.:
+ <set name="managed_apps">
+ <string>com.mine.app1</string>
+ <string>com.mine.app2</string>
+ <string>com.mine.app3</string>
+ </set>
+ """
+ tag_name = 'set'
+
+ def get(self):
+ """Get a list with the string values contained."""
+ value = []
+ for child in self._elem:
+ assert child.tag == 'string'
+ value.append(child.text)
+ return value
+
+ def set(self, value):
+ """Set from a sequence of values, each casted as a string."""
+ for child in list(self._elem):
+ self._elem.remove(child)
+ for item in value:
+ ElementTree.SubElement(self._elem, 'string').text = str(item)
+
+
+_PREF_TYPES = {c.tag_name: c for c in [BooleanPref, FloatPref, IntPref,
+ LongPref, StringPref, StringSetPref]}
+
+
+class SharedPrefs(object):
+ def __init__(self, device, package, filename):
+ """Helper object to read and update "Shared Prefs" of Android apps.
+
+ Such files typically look like, e.g.:
+
+ <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+ <map>
+ <int name="databaseVersion" value="107" />
+ <boolean name="featureEnabled" value="false" />
+ <string name="someHashValue">249b3e5af13d4db2</string>
+ </map>
+
+ Example usage:
+
+ prefs = shared_prefs.SharedPrefs(device, 'com.my.app', 'my_prefs.xml')
+ prefs.Load()
+ prefs.GetString('someHashValue') # => '249b3e5af13d4db2'
+ prefs.SetInt('databaseVersion', 42)
+ prefs.Remove('featureEnabled')
+ prefs.Commit()
+
+ The object may also be used as a context manager to automatically load and
+ commit, respectively, upon entering and leaving the context.
+
+ Args:
+ device: A DeviceUtils object.
+ package: A string with the package name of the app that owns the shared
+ preferences file.
+ filename: A string with the name of the preferences file to read/write.
+ """
+ self._device = device
+ self._xml = None
+ self._package = package
+ self._filename = filename
+ self._path = '/data/data/%s/shared_prefs/%s' % (package, filename)
+ self._changed = False
+
+ def __repr__(self):
+ """Get a useful printable representation of the object."""
+ return '<{cls} file {filename} for {package} on {device}>'.format(
+ cls=type(self).__name__, filename=self.filename, package=self.package,
+ device=str(self._device))
+
+ def __str__(self):
+ """Get the underlying xml document as a string."""
+ return _XML_DECLARATION + ElementTree.tostring(self.xml)
+
+ @property
+ def package(self):
+ """Get the package name of the app that owns the shared preferences."""
+ return self._package
+
+ @property
+ def filename(self):
+ """Get the filename of the shared preferences file."""
+ return self._filename
+
+ @property
+ def path(self):
+ """Get the full path to the shared preferences file on the device."""
+ return self._path
+
+ @property
+ def changed(self):
+ """True if properties have changed and a commit would be needed."""
+ return self._changed
+
+ @property
+ def xml(self):
+ """Get the underlying xml document as an ElementTree object."""
+ if self._xml is None:
+ self._xml = ElementTree.Element('map')
+ return self._xml
+
+ def Load(self):
+ """Load the shared preferences file from the device.
+
+ A empty xml document, which may be modified and saved on |commit|, is
+ created if the file does not already exist.
+ """
+ if self._device.FileExists(self.path):
+ self._xml = ElementTree.fromstring(
+ self._device.ReadFile(self.path, as_root=True))
+ assert self._xml.tag == 'map'
+ else:
+ self._xml = None
+ self._changed = False
+
+ def Clear(self):
+ """Clear all of the preferences contained in this object."""
+ if self._xml is not None and len(self): # only clear if not already empty
+ self._xml = None
+ self._changed = True
+
+ def Commit(self):
+ """Save the current set of preferences to the device.
+
+ Only actually saves if some preferences have been modified.
+ """
+ if not self.changed:
+ return
+ self._device.RunShellCommand(
+ ['mkdir', '-p', posixpath.dirname(self.path)],
+ as_root=True, check_return=True)
+ self._device.WriteFile(self.path, str(self), as_root=True)
+ self._device.KillAll(self.package, as_root=True, quiet=True)
+ self._changed = False
+
+ def __len__(self):
+ """Get the number of preferences in this collection."""
+ return len(self.xml)
+
+ def PropertyType(self, key):
+ """Get the type (i.e. tag name) of a property in the collection."""
+ return self._GetChild(key).tag
+
+ def HasProperty(self, key):
+ try:
+ self._GetChild(key)
+ return True
+ except KeyError:
+ return False
+
+ def GetBoolean(self, key):
+ """Get a boolean property."""
+ return BooleanPref(self._GetChild(key)).get()
+
+ def SetBoolean(self, key, value):
+ """Set a boolean property."""
+ self._SetPrefValue(key, value, BooleanPref)
+
+ def GetFloat(self, key):
+ """Get a float property."""
+ return FloatPref(self._GetChild(key)).get()
+
+ def SetFloat(self, key, value):
+ """Set a float property."""
+ self._SetPrefValue(key, value, FloatPref)
+
+ def GetInt(self, key):
+ """Get an int property."""
+ return IntPref(self._GetChild(key)).get()
+
+ def SetInt(self, key, value):
+ """Set an int property."""
+ self._SetPrefValue(key, value, IntPref)
+
+ def GetLong(self, key):
+ """Get a long property."""
+ return LongPref(self._GetChild(key)).get()
+
+ def SetLong(self, key, value):
+ """Set a long property."""
+ self._SetPrefValue(key, value, LongPref)
+
+ def GetString(self, key):
+ """Get a string property."""
+ return StringPref(self._GetChild(key)).get()
+
+ def SetString(self, key, value):
+ """Set a string property."""
+ self._SetPrefValue(key, value, StringPref)
+
+ def GetStringSet(self, key):
+ """Get a string set property."""
+ return StringSetPref(self._GetChild(key)).get()
+
+ def SetStringSet(self, key, value):
+ """Set a string set property."""
+ self._SetPrefValue(key, value, StringSetPref)
+
+ def Remove(self, key):
+ """Remove a preference from the collection."""
+ self.xml.remove(self._GetChild(key))
+
+ def AsDict(self):
+ """Return the properties and their values as a dictionary."""
+ d = {}
+ for child in self.xml:
+ pref = _PREF_TYPES[child.tag](child)
+ d[child.get('name')] = pref.get()
+ return d
+
+ def __enter__(self):
+ """Load preferences file from the device when entering a context."""
+ self.Load()
+ return self
+
+ def __exit__(self, exc_type, _exc_value, _traceback):
+ """Save preferences file to the device when leaving a context."""
+ if not exc_type:
+ self.Commit()
+
+ def _GetChild(self, key):
+ """Get the underlying xml node that holds the property of a given key.
+
+ Raises:
+ KeyError when the key is not found in the collection.
+ """
+ for child in self.xml:
+ if child.get('name') == key:
+ return child
+ raise KeyError(key)
+
+ def _SetPrefValue(self, key, value, pref_cls):
+ """Set the value of a property.
+
+ Args:
+ key: The key of the property to set.
+ value: The new value of the property.
+ pref_cls: A subclass of BasePref used to access the property.
+
+ Raises:
+ TypeError when the key already exists but with a different type.
+ """
+ try:
+ pref = pref_cls(self._GetChild(key))
+ old_value = pref.get()
+ except KeyError:
+ pref = pref_cls(ElementTree.SubElement(
+ self.xml, pref_cls.tag_name, {'name': key}))
+ old_value = None
+ if old_value != value:
+ pref.set(value)
+ self._changed = True
+ logging.info('Setting property: %s', pref)
diff --git a/build/android/pylib/device/shared_prefs_test.py b/build/android/pylib/device/shared_prefs_test.py
new file mode 100755
index 0000000..c5f0ec3
--- /dev/null
+++ b/build/android/pylib/device/shared_prefs_test.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+# Copyright 2015 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.
+
+"""
+Unit tests for the contents of shared_prefs.py (mostly SharedPrefs).
+"""
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.device import device_utils
+from pylib.device import shared_prefs
+
+sys.path.append(os.path.join(
+ constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock
+
+
+def MockDeviceWithFiles(files=None):
+ if files is None:
+ files = {}
+
+ def file_exists(path):
+ return path in files
+
+ def write_file(path, contents, **_kwargs):
+ files[path] = contents
+
+ def read_file(path, **_kwargs):
+ return files[path]
+
+ device = mock.MagicMock(spec=device_utils.DeviceUtils)
+ device.FileExists = mock.Mock(side_effect=file_exists)
+ device.WriteFile = mock.Mock(side_effect=write_file)
+ device.ReadFile = mock.Mock(side_effect=read_file)
+ return device
+
+
+class SharedPrefsTest(unittest.TestCase):
+
+ def setUp(self):
+ self.device = MockDeviceWithFiles({
+ '/data/data/com.some.package/shared_prefs/prefs.xml':
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ '<map>\n'
+ ' <int name="databaseVersion" value="107" />\n'
+ ' <boolean name="featureEnabled" value="false" />\n'
+ ' <string name="someHashValue">249b3e5af13d4db2</string>\n'
+ '</map>'})
+ self.expected_data = {'databaseVersion': 107,
+ 'featureEnabled': False,
+ 'someHashValue': '249b3e5af13d4db2'}
+
+ def testPropertyLifetime(self):
+ prefs = shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml')
+ self.assertEquals(len(prefs), 0) # collection is empty before loading
+ prefs.SetInt('myValue', 444)
+ self.assertEquals(len(prefs), 1)
+ self.assertEquals(prefs.GetInt('myValue'), 444)
+ self.assertTrue(prefs.HasProperty('myValue'))
+ prefs.Remove('myValue')
+ self.assertEquals(len(prefs), 0)
+ self.assertFalse(prefs.HasProperty('myValue'))
+ with self.assertRaises(KeyError):
+ prefs.GetInt('myValue')
+
+ def testPropertyType(self):
+ prefs = shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml')
+ prefs.SetInt('myValue', 444)
+ self.assertEquals(prefs.PropertyType('myValue'), 'int')
+ with self.assertRaises(TypeError):
+ prefs.GetString('myValue')
+ with self.assertRaises(TypeError):
+ prefs.SetString('myValue', 'hello')
+
+ def testLoad(self):
+ prefs = shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml')
+ self.assertEquals(len(prefs), 0) # collection is empty before loading
+ prefs.Load()
+ self.assertEquals(len(prefs), len(self.expected_data))
+ self.assertEquals(prefs.AsDict(), self.expected_data)
+ self.assertFalse(prefs.changed)
+
+ def testClear(self):
+ prefs = shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml')
+ prefs.Load()
+ self.assertEquals(prefs.AsDict(), self.expected_data)
+ self.assertFalse(prefs.changed)
+ prefs.Clear()
+ self.assertEquals(len(prefs), 0) # collection is empty now
+ self.assertTrue(prefs.changed)
+
+ def testCommit(self):
+ prefs = shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'other_prefs.xml')
+ self.assertFalse(self.device.FileExists(prefs.path)) # file does not exist
+ prefs.Load()
+ self.assertEquals(len(prefs), 0) # file did not exist, collection is empty
+ prefs.SetInt('magicNumber', 42)
+ prefs.SetFloat('myMetric', 3.14)
+ prefs.SetLong('bigNumner', 6000000000)
+ prefs.SetStringSet('apps', ['gmail', 'chrome', 'music'])
+ self.assertFalse(self.device.FileExists(prefs.path)) # still does not exist
+ self.assertTrue(prefs.changed)
+ prefs.Commit()
+ self.assertTrue(self.device.FileExists(prefs.path)) # should exist now
+ self.device.KillAll.assert_called_once_with(prefs.package, as_root=True,
+ quiet=True)
+ self.assertFalse(prefs.changed)
+
+ prefs = shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'other_prefs.xml')
+ self.assertEquals(len(prefs), 0) # collection is empty before loading
+ prefs.Load()
+ self.assertEquals(prefs.AsDict(), {
+ 'magicNumber': 42,
+ 'myMetric': 3.14,
+ 'bigNumner': 6000000000,
+ 'apps': ['gmail', 'chrome', 'music']}) # data survived roundtrip
+
+ def testAsContextManager_onlyReads(self):
+ with shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml') as prefs:
+ self.assertEquals(prefs.AsDict(), self.expected_data) # loaded and ready
+ self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
+
+ def testAsContextManager_readAndWrite(self):
+ with shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml') as prefs:
+ prefs.SetBoolean('featureEnabled', True)
+ prefs.Remove('someHashValue')
+ prefs.SetString('newString', 'hello')
+
+ self.assertTrue(self.device.WriteFile.called) # did write
+ with shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml') as prefs:
+ # changes persisted
+ self.assertTrue(prefs.GetBoolean('featureEnabled'))
+ self.assertFalse(prefs.HasProperty('someHashValue'))
+ self.assertEquals(prefs.GetString('newString'), 'hello')
+ self.assertTrue(prefs.HasProperty('databaseVersion')) # still there
+
+ def testAsContextManager_commitAborted(self):
+ with self.assertRaises(TypeError):
+ with shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml') as prefs:
+ prefs.SetBoolean('featureEnabled', True)
+ prefs.Remove('someHashValue')
+ prefs.SetString('newString', 'hello')
+ prefs.SetInt('newString', 123) # oops!
+
+ self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
+ with shared_prefs.SharedPrefs(
+ self.device, 'com.some.package', 'prefs.xml') as prefs:
+ # contents were not modified
+ self.assertEquals(prefs.AsDict(), self.expected_data)
+
+if __name__ == '__main__':
+ logging.getLogger().setLevel(logging.DEBUG)
+ unittest.main(verbosity=2)
diff --git a/build/android/pylib/gtest/filter/net_unittests_disabled b/build/android/pylib/gtest/filter/net_unittests_disabled
index 2632e7c..75a1c86 100644
--- a/build/android/pylib/gtest/filter/net_unittests_disabled
+++ b/build/android/pylib/gtest/filter/net_unittests_disabled
@@ -1,11 +1,5 @@
# List of suppressions.
-# Bug: 171812
-MultiThreadedCertVerifierTest.CancelRequest
-
-# Bug: 380340
-SSLServerSocketTest.Handshake
-
PythonUtils.PythonRunTime
VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/0
VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/1
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py
index 6ce0fb1..6e332c7 100644
--- a/build/android/pylib/gtest/gtest_config.py
+++ b/build/android/pylib/gtest/gtest_config.py
@@ -32,6 +32,7 @@
'gpu_unittests',
'ipc_tests',
'media_unittests',
+ 'midi_unittests',
'net_unittests',
'sandbox_linux_unittests',
'skia_unittests',
diff --git a/build/android/pylib/gtest/local_device_gtest_run.py b/build/android/pylib/gtest/local_device_gtest_run.py
index fd143d6..4241e85 100644
--- a/build/android/pylib/gtest/local_device_gtest_run.py
+++ b/build/android/pylib/gtest/local_device_gtest_run.py
@@ -21,9 +21,9 @@
_COMMAND_LINE_FLAGS_SUPPORTED = True
_EXTRA_COMMAND_LINE_FILE = (
- 'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile')
+ 'org.chromium.native_test.NativeTestActivity.CommandLineFile')
_EXTRA_COMMAND_LINE_FLAGS = (
- 'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags')
+ 'org.chromium.native_test.NativeTestActivity.CommandLineFlags')
_MAX_SHARD_SIZE = 256
diff --git a/build/android/pylib/gtest/setup.py b/build/android/pylib/gtest/setup.py
index 44662d0..2676152 100644
--- a/build/android/pylib/gtest/setup.py
+++ b/build/android/pylib/gtest/setup.py
@@ -37,6 +37,7 @@
'content_unittests': 'content/content_unittests.isolate',
'media_perftests': 'media/media_perftests.isolate',
'media_unittests': 'media/media_unittests.isolate',
+ 'midi_unittests': 'media/midi/midi_unittests.isolate',
'net_unittests': 'net/net_unittests.isolate',
'sql_unittests': 'sql/sql_unittests.isolate',
'sync_unit_tests': 'sync/sync_unit_tests.isolate',
diff --git a/build/android/pylib/gtest/test_package_apk.py b/build/android/pylib/gtest/test_package_apk.py
index 8da3c74..9672f7a 100644
--- a/build/android/pylib/gtest/test_package_apk.py
+++ b/build/android/pylib/gtest/test_package_apk.py
@@ -51,7 +51,7 @@
def _GetFifo(self):
# The test.fifo path is determined by:
# testing/android/native_test/java/src/org/chromium/native_test/
- # ChromeNativeTestActivity.java and
+ # NativeTestActivity.java and
# testing/android/native_test_launcher.cc
return '/data/data/' + self._package_info.package + '/files/test.fifo'
diff --git a/build/android/pylib/host_driven/test_case.py b/build/android/pylib/host_driven/test_case.py
index a7c6a18..6ff4c5f 100644
--- a/build/android/pylib/host_driven/test_case.py
+++ b/build/android/pylib/host_driven/test_case.py
@@ -68,9 +68,9 @@
def SetUp(self, device, shard_index, ports_to_forward=None):
if not ports_to_forward:
ports_to_forward = []
- self.device_id = device
+ self.device = device
self.shard_index = shard_index
- self.device = device_utils.DeviceUtils(self.device_id)
+ self.device_id = str(self.device)
if ports_to_forward:
self.ports_to_forward = ports_to_forward
@@ -117,10 +117,9 @@
# TODO(bulach): move this to SetUp() stage.
self.__StartForwarder()
- java_test_runner = test_runner.TestRunner(self.instrumentation_options,
- self.device_id,
- self.shard_index, test_pkg,
- additional_flags=additional_flags)
+ java_test_runner = test_runner.TestRunner(
+ self.instrumentation_options, self.device, self.shard_index,
+ test_pkg, additional_flags=additional_flags)
try:
java_test_runner.SetUp()
return java_test_runner.RunTest(test)[0]
diff --git a/build/android/pylib/host_driven/test_runner.py b/build/android/pylib/host_driven/test_runner.py
index 5e175bc..8620aa1 100644
--- a/build/android/pylib/host_driven/test_runner.py
+++ b/build/android/pylib/host_driven/test_runner.py
@@ -86,7 +86,7 @@
exception_raised = False
try:
- test.SetUp(str(self.device), self.shard_index)
+ test.SetUp(self.device, self.shard_index)
except Exception:
logging.exception(
'Caught exception while trying to run SetUp() for test: ' +
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index ccc0e72..0633f14 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -30,6 +30,17 @@
_DEFAULT_ANNOTATIONS = [
'Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
'EnormousTest', 'IntegrationTest']
+_EXTRA_ENABLE_HTTP_SERVER = (
+ 'org.chromium.chrome.test.ChromeInstrumentationTestRunner.'
+ + 'EnableTestHttpServer')
+_EXTRA_DRIVER_TEST_LIST = (
+ 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList')
+_EXTRA_DRIVER_TEST_LIST_FILE = (
+ 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile')
+_EXTRA_DRIVER_TARGET_PACKAGE = (
+ 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage')
+_EXTRA_DRIVER_TARGET_CLASS = (
+ 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass')
_NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE)
_PICKLE_FORMAT_VERSION = 10
@@ -130,29 +141,35 @@
self._apk_under_test = None
self._package_info = None
+ self._suite = None
self._test_apk = None
self._test_jar = None
self._test_package = None
self._test_runner = None
self._test_support_apk = None
- self.__initializeApkAttributes(args, error_func)
+ self._initializeApkAttributes(args, error_func)
self._data_deps = None
self._isolate_abs_path = None
self._isolate_delegate = None
self._isolated_abs_path = None
self._test_data = None
- self.__initializeDataDependencyAttributes(args, isolate_delegate)
+ self._initializeDataDependencyAttributes(args, isolate_delegate)
self._annotations = None
self._excluded_annotations = None
self._test_filter = None
- self.__initializeTestFilterAttributes(args)
+ self._initializeTestFilterAttributes(args)
self._flags = None
- self.__initializeFlagAttributes(args)
+ self._initializeFlagAttributes(args)
- def __initializeApkAttributes(self, args, error_func):
+ self._driver_apk = None
+ self._driver_package = None
+ self._driver_name = None
+ self._initializeDriverAttributes()
+
+ def _initializeApkAttributes(self, args, error_func):
if args.apk_under_test.endswith('.apk'):
self._apk_under_test = args.apk_under_test
else:
@@ -164,20 +181,20 @@
error_func('Unable to find APK under test: %s' % self._apk_under_test)
if args.test_apk.endswith('.apk'):
- test_apk_root = os.path.splitext(os.path.basename(args.test_apk))[0]
+ self._suite = os.path.splitext(os.path.basename(args.test_apk))[0]
self._test_apk = args.test_apk
else:
- test_apk_root = args.test_apk
+ self._suite = args.test_apk
self._test_apk = os.path.join(
constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
'%s.apk' % args.test_apk)
self._test_jar = os.path.join(
constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR,
- '%s.jar' % test_apk_root)
+ '%s.jar' % self._suite)
self._test_support_apk = os.path.join(
constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR,
- '%sSupport.apk' % test_apk_root)
+ '%sSupport.apk' % self._suite)
if not os.path.exists(self._test_apk):
error_func('Unable to find test APK: %s' % self._test_apk)
@@ -194,7 +211,7 @@
if not self._package_info:
logging.warning('Unable to find package info for %s', self._test_package)
- def __initializeDataDependencyAttributes(self, args, isolate_delegate):
+ def _initializeDataDependencyAttributes(self, args, isolate_delegate):
self._data_deps = []
if args.isolate_file_path:
self._isolate_abs_path = os.path.abspath(args.isolate_file_path)
@@ -215,7 +232,7 @@
if not self._isolate_delegate and not self._test_data:
logging.warning('No data dependencies will be pushed.')
- def __initializeTestFilterAttributes(self, args):
+ def _initializeTestFilterAttributes(self, args):
self._test_filter = args.test_filter
def annotation_dict_element(a):
@@ -240,7 +257,7 @@
else:
self._excluded_annotations = {}
- def __initializeFlagAttributes(self, args):
+ def _initializeFlagAttributes(self, args):
self._flags = ['--disable-fre', '--enable-test-intents']
# TODO(jbudorick): Transition "--device-flags" to "--device-flags-file"
if hasattr(args, 'device_flags') and args.device_flags:
@@ -252,9 +269,17 @@
stripped_lines = (l.strip() for l in device_flags_file)
self._flags.extend([flag for flag in stripped_lines if flag])
- @property
- def suite(self):
- return 'instrumentation'
+ def _initializeDriverAttributes(self):
+ self._driver_apk = os.path.join(
+ constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
+ 'OnDeviceInstrumentationDriver.apk')
+ if os.path.exists(self._driver_apk):
+ self._driver_package = apk_helper.GetPackageName(
+ self._driver_apk)
+ self._driver_name = apk_helper.GetInstrumentationName(
+ self._driver_apk)
+ else:
+ self._driver_apk = None
@property
def apk_under_test(self):
@@ -265,10 +290,26 @@
return self._flags
@property
+ def driver_apk(self):
+ return self._driver_apk
+
+ @property
+ def driver_package(self):
+ return self._driver_package
+
+ @property
+ def driver_name(self):
+ return self._driver_name
+
+ @property
def package_info(self):
return self._package_info
@property
+ def suite(self):
+ return self._suite
+
+ @property
def test_apk(self):
return self._test_apk
@@ -446,6 +487,28 @@
return inflated_tests
@staticmethod
+ def GetHttpServerEnvironmentVars():
+ return {
+ _EXTRA_ENABLE_HTTP_SERVER: None,
+ }
+
+ def GetDriverEnvironmentVars(
+ self, test_list=None, test_list_file_path=None):
+ env = {
+ _EXTRA_DRIVER_TARGET_PACKAGE: self.test_package,
+ _EXTRA_DRIVER_TARGET_CLASS: self.test_runner,
+ }
+
+ if test_list:
+ env[_EXTRA_DRIVER_TEST_LIST] = ','.join(test_list)
+
+ if test_list_file_path:
+ env[_EXTRA_DRIVER_TEST_LIST_FILE] = (
+ os.path.basename(test_list_file_path))
+
+ return env
+
+ @staticmethod
def ParseAmInstrumentRawOutput(raw_output):
return ParseAmInstrumentRawOutput(raw_output)
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index adc1037..e388fce 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -130,22 +130,41 @@
#override
def _RunTest(self, device, test):
- test_name = self._GetTestName(test)
- logging.info('preparing to run %s: %s' % (test_name, test))
+ extras = self._test_instance.GetHttpServerEnvironmentVars()
- extras = {
- 'class': test_name,
- 'org.chromium.chrome.test.ChromeInstrumentationTestRunner'
- '.EnableTestHttpServer': '',
- }
- timeout = self._GetTimeoutFromAnnotations(test['annotations'], test_name)
+ if isinstance(test, list):
+ if not self._test_instance.driver_apk:
+ raise Exception('driver_apk does not exist. '
+ 'Please build it and try again.')
+
+ def name_and_timeout(t):
+ n = self._GetTestName(t)
+ i = self._GetTimeoutFromAnnotations(t['annotations'], n)
+ return (n, i)
+
+ test_names, timeouts = zip(*(name_and_timeout(t) for t in test))
+
+ test_name = ','.join(test_names)
+ target = '%s/%s' % (
+ self._test_instance.driver_package,
+ self._test_instance.driver_name)
+ extras.update(
+ self._test_instance.GetDriverEnvironmentVars(
+ test_list=test_names))
+ timeout = sum(timeouts)
+ else:
+ test_name = self._GetTestName(test)
+ target = '%s/%s' % (
+ self._test_instance.test_package, self._test_instance.test_runner)
+ extras['class'] = test_name
+ timeout = self._GetTimeoutFromAnnotations(test['annotations'], test_name)
+
+ logging.info('preparing to run %s: %s' % (test_name, test))
time_ms = lambda: int(time.time() * 1e3)
start_ms = time_ms()
output = device.StartInstrumentation(
- '%s/%s' % (self._test_instance.test_package,
- self._test_instance.test_runner),
- raw=True, extras=extras, timeout=timeout, retries=0)
+ target, raw=True, extras=extras, timeout=timeout, retries=0)
duration_ms = time_ms() - start_ms
# TODO(jbudorick): Make instrumentation tests output a JSON so this
diff --git a/build/android/pylib/perf/perf_control_unittest.py b/build/android/pylib/perf/perf_control_unittest.py
index dd7cb88..69b8b46 100644
--- a/build/android/pylib/perf/perf_control_unittest.py
+++ b/build/android/pylib/perf/perf_control_unittest.py
@@ -9,7 +9,6 @@
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
-from pylib import android_commands
from pylib.device import device_utils
from pylib.perf import perf_control
@@ -18,10 +17,9 @@
if not os.getenv('BUILDTYPE'):
os.environ['BUILDTYPE'] = 'Debug'
- devices = android_commands.GetAttachedDevices()
+ devices = device_utils.DeviceUtils.HealthyDevices()
self.assertGreater(len(devices), 0, 'No device attached!')
- self._device = device_utils.DeviceUtils(
- android_commands.AndroidCommands(device=devices[0]))
+ self._device = devices[0]
def testHighPerfMode(self):
perf = perf_control.PerfControl(self._device)
diff --git a/build/android/pylib/perf/setup.py b/build/android/pylib/perf/setup.py
index 8884d60..8e1fc28 100644
--- a/build/android/pylib/perf/setup.py
+++ b/build/android/pylib/perf/setup.py
@@ -10,10 +10,10 @@
import os
import shutil
-from pylib import android_commands
from pylib import constants
from pylib import forwarder
from pylib.device import device_list
+from pylib.device import device_utils
from pylib.perf import test_runner
from pylib.utils import test_environment
@@ -22,10 +22,11 @@
devices_path = os.path.join(os.environ.get('CHROMIUM_OUT_DIR', 'out'),
device_list.LAST_DEVICES_FILENAME)
try:
- devices = device_list.GetPersistentDeviceList(devices_path)
+ devices = [device_utils.DeviceUtils(s)
+ for s in device_list.GetPersistentDeviceList(devices_path)]
except IOError as e:
logging.error('Unable to find %s [%s]', devices_path, e)
- devices = android_commands.GetAttachedDevices()
+ devices = device_utils.DeviceUtils.HealthyDevices()
return sorted(devices)
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py
index b69c7b2..d055ae0 100644
--- a/build/android/pylib/remote/device/remote_device_environment.py
+++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -78,7 +78,8 @@
self._remote_device_minimum_os = device_json.get(
'remote_device_minimum_os', None)
self._remote_device_os = device_json.get('remote_device_os', None)
- self._remote_device_timeout = device_json.get('remote_device_timeout', None)
+ self._remote_device_timeout = device_json.get(
+ 'remote_device_timeout', None)
self._results_path = device_json.get('results_path', None)
self._runner_package = device_json.get('runner_package', None)
self._runner_type = device_json.get('runner_type', None)
@@ -330,11 +331,6 @@
return self._network_config
@property
- def only_output_failures(self):
- # TODO(jbudorick): Remove this once b/18981674 is fixed.
- return True
-
- @property
def results_path(self):
return self._results_path
diff --git a/build/android/pylib/remote/device/remote_device_gtest_run.py b/build/android/pylib/remote/device/remote_device_gtest_run.py
index 973eebe..ec747f1 100644
--- a/build/android/pylib/remote/device/remote_device_gtest_run.py
+++ b/build/android/pylib/remote/device/remote_device_gtest_run.py
@@ -17,18 +17,14 @@
_EXTRA_COMMAND_LINE_FILE = (
- 'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile')
-# TODO(jbudorick): Remove this extra when b/18981674 is fixed.
-_EXTRA_ONLY_OUTPUT_FAILURES = (
- 'org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner.'
- 'OnlyOutputFailures')
+ 'org.chromium.native_test.NativeTestActivity.CommandLineFile')
class RemoteDeviceGtestTestRun(remote_device_test_run.RemoteDeviceTestRun):
"""Run gtests and uirobot tests on a remote device."""
DEFAULT_RUNNER_PACKAGE = (
- 'org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner')
+ 'org.chromium.native_test.NativeTestInstrumentationTestRunner')
#override
def TestPackage(self):
@@ -61,8 +57,6 @@
env_vars[_EXTRA_COMMAND_LINE_FILE] = os.path.basename(flag_file.name)
self._test_instance._data_deps.append(
(os.path.abspath(flag_file.name), None))
- if self._env.only_output_failures:
- env_vars[_EXTRA_ONLY_OUTPUT_FAILURES] = None
self._AmInstrumentTestSetup(
dummy_app_path, self._test_instance.apk, runner_package,
environment_variables=env_vars)
@@ -73,15 +67,13 @@
def _ParseTestResults(self):
logging.info('Parsing results from stdout.')
results = base_test_result.TestRunResults()
- output = self._results['results']['output'].splitlines()
+ output = self._GetRawTestOutput().splitlines()
output = (l[len(self._INSTRUMENTATION_STREAM_LEADER):] for l in output
if l.startswith(self._INSTRUMENTATION_STREAM_LEADER))
results_list = self._test_instance.ParseGTestOutput(output)
results.AddResults(results_list)
- if self._env.only_output_failures:
- logging.info('See logcat for more results information.')
if not self._results['results']['pass']:
results.AddResult(base_test_result.BaseTestResult(
'Remote Service detected error.',
base_test_result.ResultType.FAIL))
- return results
\ No newline at end of file
+ return results
diff --git a/build/android/pylib/remote/device/remote_device_helper.py b/build/android/pylib/remote/device/remote_device_helper.py
index 5b1411e..896ae99 100644
--- a/build/android/pylib/remote/device/remote_device_helper.py
+++ b/build/android/pylib/remote/device/remote_device_helper.py
@@ -20,4 +20,5 @@
error_msg: Error message to display if bad response is seen.
"""
if response.status_code != 200:
- raise RemoteDeviceError(error_msg)
+ raise RemoteDeviceError(
+ '%s (%d: %s)' % (error_msg, response.status_code, response.reason))
diff --git a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
index fe173a4..0b0afb1 100644
--- a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
@@ -8,6 +8,7 @@
import os
import tempfile
+from pylib import constants
from pylib.base import base_test_result
from pylib.remote.device import remote_device_test_run
from pylib.utils import apk_helper
@@ -25,9 +26,33 @@
def _TriggerSetUp(self):
"""Set up the triggering of a test run."""
logging.info('Triggering test run.')
- self._AmInstrumentTestSetup(
- self._test_instance._apk_under_test, self._test_instance.test_apk,
- self._test_instance.test_runner, environment_variables={})
+
+ with tempfile.NamedTemporaryFile(suffix='.txt') as test_list_file:
+ tests = self._test_instance.GetTests()
+ logging.debug('preparing to run %d instrumentation tests remotely:',
+ len(tests))
+ for t in tests:
+ test_name = '%s#%s' % (t['class'], t['method'])
+ logging.debug(' %s', test_name)
+ test_list_file.write('%s\n' % test_name)
+ test_list_file.flush()
+ self._test_instance._data_deps.append(
+ (os.path.abspath(test_list_file.name), None))
+
+ env_vars = self._test_instance.GetDriverEnvironmentVars(
+ test_list_file_path=test_list_file.name)
+ env_vars.update(self._test_instance.GetHttpServerEnvironmentVars())
+
+ logging.debug('extras:')
+ for k, v in env_vars.iteritems():
+ logging.debug(' %s: %s', k, v)
+
+ self._AmInstrumentTestSetup(
+ self._test_instance.apk_under_test,
+ self._test_instance.driver_apk,
+ self._test_instance.driver_name,
+ environment_variables=env_vars,
+ extra_apks=[self._test_instance.test_apk])
#override
def _ParseTestResults(self):
@@ -35,7 +60,7 @@
r = base_test_result.TestRunResults()
result_code, result_bundle, statuses = (
self._test_instance.ParseAmInstrumentRawOutput(
- self._results['results']['output'].splitlines()))
+ self._GetRawTestOutput().splitlines()))
result = self._test_instance.GenerateTestResults(
result_code, result_bundle, statuses, 0, 0)
diff --git a/build/android/pylib/remote/device/remote_device_test_run.py b/build/android/pylib/remote/device/remote_device_test_run.py
index 7aa91ae..60a0664 100644
--- a/build/android/pylib/remote/device/remote_device_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -29,6 +29,8 @@
COMPLETE = 'complete'
HEARTBEAT_INTERVAL = 300
+ _RESULTS_FILE = 'appurify_results/result.txt'
+
def __init__(self, env, test_instance):
"""Constructor.
@@ -173,7 +175,7 @@
"""Download the test results from remote device service.
Args:
- results_path: path to download results to.
+ results_path: Path to download appurify results zipfile.
"""
if results_path:
logging.info('Downloading results to %s.' % results_path)
@@ -184,6 +186,21 @@
appurify_sanitized.utils.wget(self._results['results']['url'],
results_path)
+ def _GetRawTestOutput(self):
+ """Returns the test output."""
+ # TODO(mikecase): Remove getting results from zip when b/18981674 is fixed.
+ results_zipfile = self._env.results_path
+ if results_zipfile and os.path.exists(results_zipfile):
+ with zipfile.ZipFile(results_zipfile) as z:
+ with z.open(self._RESULTS_FILE, 'r') as r:
+ return r.read()
+ else:
+ logging.warning(
+ 'If the test output is too long, some test results may get cut off.')
+ logging.warning(
+ 'Use the --results-path option to ensure you get the full results.')
+ return self._results['results']['output']
+
def _GetTestStatus(self, test_run_id):
"""Checks the state of the test, and sets self._results
@@ -201,7 +218,7 @@
return self._results['status']
def _AmInstrumentTestSetup(self, app_path, test_path, runner_package,
- environment_variables):
+ environment_variables, extra_apks=None):
config = {'runner': runner_package}
if environment_variables:
config['environment_vars'] = ','.join(
@@ -213,6 +230,7 @@
if data_deps:
with tempfile.NamedTemporaryFile(suffix='.zip') as test_with_deps:
sdcard_files = []
+ additional_apks = []
host_test = os.path.basename(test_path)
with zipfile.ZipFile(test_with_deps.name, 'w') as zip_file:
zip_file.write(test_path, host_test, zipfile.ZIP_DEFLATED)
@@ -223,8 +241,14 @@
else:
zip_utils.WriteToZipFile(zip_file, h, os.path.basename(h))
sdcard_files.append(os.path.basename(h))
+ for a in extra_apks or ():
+ zip_utils.WriteToZipFile(zip_file, a, os.path.basename(a));
+ additional_apks.append(os.path.basename(a))
+
config['sdcard_files'] = ','.join(sdcard_files)
config['host_test'] = host_test
+ if additional_apks:
+ config['additional_apks'] = ','.join(additional_apks)
self._test_id = self._UploadTestToDevice(
'robotium', test_with_deps.name, app_id=self._app_id)
else:
@@ -238,7 +262,8 @@
def _UploadAppToDevice(self, app_path):
"""Upload app to device."""
- logging.info('Uploading %s to remote service.', app_path)
+ logging.info('Uploading %s to remote service as %s.', app_path,
+ self._test_instance.suite)
with open(app_path, 'rb') as apk_src:
with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
logging.WARNING):
@@ -297,4 +322,4 @@
config_response = appurify_sanitized.api.config_upload(
self._env.token, config, self._test_id)
remote_device_helper.TestHttpResponse(
- config_response, 'Unable to upload test config.')
\ No newline at end of file
+ config_response, 'Unable to upload test config.')
diff --git a/build/android/pylib/utils/emulator.py b/build/android/pylib/utils/emulator.py
index 26b9109..635462f 100644
--- a/build/android/pylib/utils/emulator.py
+++ b/build/android/pylib/utils/emulator.py
@@ -15,7 +15,6 @@
import time
# TODO(craigdh): Move these pylib dependencies to pylib/utils/.
-from pylib import android_commands
from pylib import cmd_helper
from pylib import constants
from pylib import pexpect
@@ -90,14 +89,14 @@
running but a device slot is taken. A little bot trouble and and
we're out of room forever.
"""
- emulators = android_commands.GetAttachedDevices(hardware=False)
+ emulators = [d for d in device_utils.HealthyDevices() if d.adb.is_emulator]
if not emulators:
return
- for emu_name in emulators:
- cmd_helper.RunCmd(['adb', '-s', emu_name, 'emu', 'kill'])
+ for e in emulators:
+ e.adb.Emu(['kill'])
logging.info('Emulator killing is async; give a few seconds for all to die.')
for _ in range(5):
- if not android_commands.GetAttachedDevices(hardware=False):
+ if not any(d.adb.is_emulator for d in device_utils.HealthyDevices()):
return
time.sleep(1)
@@ -141,9 +140,9 @@
def _GetAvailablePort():
"""Returns an available TCP port for the console."""
used_ports = []
- emulators = android_commands.GetAttachedDevices(hardware=False)
+ emulators = [d for d in device_utils.HealthyDevices() if d.adb.is_emulator]
for emulator in emulators:
- used_ports.append(emulator.split('-')[1])
+ used_ports.append(emulator.adb.GetDeviceSerial().split('-')[1])
for port in PortPool.port_range():
if str(port) not in used_ports:
return port
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py
index 90d5ca0..cac39d8 100644
--- a/build/android/pylib/utils/isolator.py
+++ b/build/android/pylib/utils/isolator.py
@@ -36,6 +36,7 @@
'enable_plugins': '0',
'fastbuild': '0',
'icu_use_data_file_flag': '1',
+ 'kasko': '0',
'lsan': '0',
'msan': '0',
# TODO(maruel): This may not always be true.
diff --git a/build/android/pylib/utils/md5sum.py b/build/android/pylib/utils/md5sum.py
index 4d7d0b0..d59245c 100644
--- a/build/android/pylib/utils/md5sum.py
+++ b/build/android/pylib/utils/md5sum.py
@@ -34,9 +34,11 @@
if isinstance(paths, basestring):
paths = [paths]
- out = cmd_helper.GetCmdOutput(
- [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host')] +
- [p for p in paths])
+ md5sum_bin_host_path = os.path.join(
+ constants.GetOutDirectory(), 'md5sum_bin_host')
+ if not os.path.exists(md5sum_bin_host_path):
+ raise IOError('File not built: %s' % md5sum_bin_host_path)
+ out = cmd_helper.GetCmdOutput([md5sum_bin_host_path] + [p for p in paths])
return _ParseMd5SumOutput(out.splitlines())
@@ -53,9 +55,10 @@
paths = [paths]
if not device.FileExists(MD5SUM_DEVICE_BIN_PATH):
- device.adb.Push(
- os.path.join(constants.GetOutDirectory(), 'md5sum_dist'),
- MD5SUM_DEVICE_LIB_PATH)
+ md5sum_dist_path = os.path.join(constants.GetOutDirectory(), 'md5sum_dist')
+ if not os.path.exists(md5sum_dist_path):
+ raise IOError('File not built: %s' % md5sum_dist_path)
+ device.adb.Push(md5sum_dist_path, MD5SUM_DEVICE_LIB_PATH)
out = []
diff --git a/build/android/pylib/utils/md5sum_test.py b/build/android/pylib/utils/md5sum_test.py
index de9cd35..5bdee32 100755
--- a/build/android/pylib/utils/md5sum_test.py
+++ b/build/android/pylib/utils/md5sum_test.py
@@ -24,6 +24,8 @@
self._patchers = [
mock.patch('pylib.constants.GetOutDirectory',
new=mock.Mock(return_value=TEST_OUT_DIR)),
+ mock.patch('os.path.exists',
+ new=mock.Mock(return_value=True)),
]
for p in self._patchers:
p.start()
diff --git a/build/android/setup.gyp b/build/android/setup.gyp
index 7dce19d..b3c3422 100644
--- a/build/android/setup.gyp
+++ b/build/android/setup.gyp
@@ -16,7 +16,7 @@
{
'destination': '<(SHARED_LIB_DIR)/',
'files': [
- '<(android_stlport_libs_dir)/libstlport_shared.so',
+ '<(android_libcpp_libs_dir)/libc++_shared.so',
],
},
],
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index c54ed28..b9d2a3f 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -16,7 +16,6 @@
import threading
import unittest
-from pylib import android_commands
from pylib import constants
from pylib import forwarder
from pylib import ports
@@ -25,6 +24,8 @@
from pylib.base import test_dispatcher
from pylib.base import test_instance_factory
from pylib.base import test_run_factory
+from pylib.device import device_errors
+from pylib.device import device_utils
from pylib.gtest import gtest_config
from pylib.gtest import setup as gtest_setup
from pylib.gtest import test_options as gtest_test_options
@@ -110,7 +111,7 @@
if args.build_directory:
constants.SetBuildDirectory(args.build_directory)
if args.output_directory:
- constants.SetOutputDirectort(args.output_directory)
+ constants.SetOutputDirectory(args.output_directory)
if args.adb_path:
constants.SetAdbPath(args.adb_path)
# Some things such as Forwarder require ADB to be in the environment path.
@@ -867,18 +868,19 @@
Returns:
A list of attached devices.
"""
- attached_devices = []
-
- attached_devices = android_commands.GetAttachedDevices()
+ attached_devices = device_utils.DeviceUtils.HealthyDevices()
if test_device:
- assert test_device in attached_devices, (
- 'Did not find device %s among attached device. Attached devices: %s'
- % (test_device, ', '.join(attached_devices)))
- attached_devices = [test_device]
+ test_device = [d for d in attached_devices if d == test_device]
+ if not test_device:
+ raise device_errors.DeviceUnreachableError(
+ 'Did not find device %s among attached device. Attached devices: %s'
+ % (test_device, ', '.join(attached_devices)))
+ return test_device
- assert attached_devices, 'No devices attached.'
-
- return sorted(attached_devices)
+ else:
+ if not attached_devices:
+ raise device_errors.NoDevicesError()
+ return sorted(attached_devices)
def RunTestsCommand(args, parser):
diff --git a/build/apk_test.gypi b/build/apk_test.gypi
index 792d92c..3a66e3b 100644
--- a/build/apk_test.gypi
+++ b/build/apk_test.gypi
@@ -22,6 +22,7 @@
'<(DEPTH)/base/base.gyp:base_java',
'<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
'<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk',
+ '<(DEPTH)/testing/android/appurify_support.gyp:appurify_support_java',
'<(DEPTH)/tools/android/android_tools.gyp:android_tools',
],
'conditions': [
diff --git a/build/common.gypi b/build/common.gypi
index c5a8fac..a406248 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -173,6 +173,7 @@
# The system root for cross-compiles. Default: none.
'sysroot%': '',
+ 'use_sysroot%': 0,
'chroot_cmd%': '',
# The system libdir used for this ABI.
@@ -416,9 +417,6 @@
# See https://code.google.com/p/sawbuck/wiki/SyzyASanHowTo
'syzyasan%': 0,
- # Enable crash reporting via Kasko.
- 'kasko%': 0,
-
# Enable building with LSan (Clang's -fsanitize=leak option).
# -fsanitize=leak only works with clang, but lsan=1 implies clang=1
# See https://sites.google.com/a/chromium.org/dev/developers/testing/leaksanitizer
@@ -941,7 +939,7 @@
'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_arm-sysroot',
}], # OS=="linux" and target_arch=="arm" and chromeos==0
- ['OS=="linux" and branding=="Chrome" and buildtype=="Official" and chromeos==0', {
+ ['OS=="linux" and ((branding=="Chrome" and buildtype=="Official" and chromeos==0) or use_sysroot==1)' , {
'conditions': [
['target_arch=="x64"', {
'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_amd64-sysroot',
@@ -1011,6 +1009,15 @@
}, {
'sas_dll_path%': '<(DEPTH)/third_party/platformsdk_win7/files/redist/x86',
}],
+
+ # Enable crash reporting via Kasko.
+ ['OS=="win" and target_arch=="ia32"', {
+ # TODO(erikwright): This should be disabled after a single ship on Canary channel.
+ 'kasko%': 1,
+ }, {
+ 'kasko%': 0,
+ }],
+
],
# Setting this to '0' will cause V8's startup snapshot to be
@@ -1688,7 +1695,7 @@
'android_ndk_absolute_root%': '<(android_ndk_absolute_root)',
'android_sdk_root%': '<(android_sdk_root)',
'android_sdk_version%': '<(android_sdk_version)',
- 'android_stlport_root': '<(android_ndk_root)/sources/cxx-stl/stlport',
+ 'android_libcpp_root': '<(android_ndk_root)/sources/cxx-stl/llvm-libc++',
'host_os%': '<(host_os)',
'android_sdk%': '<(android_sdk_root)/platforms/android-<(android_sdk_version)',
@@ -1764,9 +1771,9 @@
'android_sdk%': '<(android_sdk)',
'android_sdk_jar%': '<(android_sdk)/android.jar',
- 'android_stlport_root': '<(android_stlport_root)',
- 'android_stlport_include': '<(android_stlport_root)/stlport',
- 'android_stlport_libs_dir': '<(android_stlport_root)/libs/<(android_app_abi)',
+ 'android_libcpp_root': '<(android_libcpp_root)',
+ 'android_libcpp_include': '<(android_libcpp_root)/libcxx/include',
+ 'android_libcpp_libs_dir': '<(android_libcpp_root)/libs/<(android_app_abi)',
'host_os%': '<(host_os)',
# Location of the "objcopy" binary, used by both gyp and scripts.
@@ -1929,9 +1936,14 @@
},{
'winsdk_arch%': '<(target_arch)',
}],
- ['component=="shared_library"', {
+ ['component=="shared_library" or MSVS_VERSION == "2015"', {
+ # TODO(scottmg): The allocator shimming doesn't work on the 2015 CRT
+ # and we are hoping to be able to remove it if an additional feature
+ # lands in the 2015 CRT API. For now, don't shim and revisit once
+ # VS2015 is RTM: http://crbug.com/481611.
'win_use_allocator_shim%': 0,
- },{
+ }],
+ ['component=="static_library"', {
# Turn on multiple dll by default on Windows when in static_library.
'chrome_multiple_dll%': 1,
}],
@@ -2168,17 +2180,23 @@
],
},
'clang_dynlib_flags%': '-Xclang -load -Xclang <(clang_lib_path) ',
+ 'clang_plugin_args%': '',
}, { # OS == "win"
# On Windows, the plugin is built directly into clang, so there's
# no need to load it dynamically.
'clang_dynlib_flags%': '',
+
+ # Don't error on plugin warnings on Windows until pre-existing warnings
+ # are cleaned up. https://crbug.com/467287
+ 'clang_plugin_args%': '-Xclang -plugin-arg-find-bad-constructs -Xclang warn-only',
}]
],
},
# If you change these, also change build/config/clang/BUILD.gn.
'clang_chrome_plugins_flags%':
'<(clang_dynlib_flags)'
- '-Xclang -add-plugin -Xclang find-bad-constructs',
+ '-Xclang -add-plugin -Xclang find-bad-constructs '
+ '<(clang_plugin_args)',
}],
['asan==1 or msan==1 or lsan==1 or tsan==1', {
'clang%': 1,
@@ -4085,9 +4103,6 @@
'cflags!': [
'-fstack-protector', # stack protector is always enabled on arm64.
],
- 'ldflags': [
- '-fuse-ld=gold',
- ],
}],
],
}],
@@ -4630,9 +4645,9 @@
# Figure this out early since it needs symbols from libgcc.a, so it
# has to be before that in the set of libraries.
['component=="shared_library"', {
- 'android_stlport_library': 'stlport_shared',
+ 'android_libcpp_library': 'c++_shared',
}, {
- 'android_stlport_library': 'stlport_static',
+ 'android_libcpp_library': 'c++_static',
}],
],
@@ -4712,17 +4727,17 @@
'-finline-limit=64',
'<@(release_extra_cflags)',
'--sysroot=<(android_ndk_sysroot)',
- # NOTE: The stlport header include paths below are specified in
+ # NOTE: The libc++ header include paths below are specified in
# cflags rather than include_dirs because they need to come
# after include_dirs.
# The include ordering here is important; change with caution.
- '-isystem<(android_stlport_include)',
+ '-isystem<(android_libcpp_include)',
+ '-isystem<(android_ndk_root)/sources/cxx-stl/llvm-libc++abi/libcxxabi/include',
+ '-isystem<(android_ndk_root)/sources/android/support/include',
],
'defines': [
'ANDROID',
'__GNU_SOURCE=1', # Necessary for clone()
- 'USE_STLPORT=1',
- '_STLP_USE_PTR_SPECIALIZATIONS=1',
'CHROME_BUILD_ID="<(chrome_build_id)"',
# The NDK has these things, but doesn't define the constants
# to say that it does. Define them here instead.
@@ -4735,11 +4750,11 @@
'-Wl,--no-undefined',
'--sysroot=<(android_ndk_sysroot)',
'-nostdlib',
- '-L<(android_stlport_libs_dir)',
- # Don't allow visible symbols from libgcc or stlport to be
+ '-L<(android_libcpp_libs_dir)',
+ # Don't allow visible symbols from libgcc or libc++ to be
# re-exported.
'-Wl,--exclude-libs=libgcc.a',
- '-Wl,--exclude-libs=libstlport_static.a',
+ '-Wl,--exclude-libs=libc++_static.a',
# Don't allow visible symbols from libraries that contain
# assembly code with symbols that aren't hidden properly.
# http://crbug.com/448386
@@ -4752,7 +4767,8 @@
'-Wl,--exclude-libs=libvpx.a',
],
'libraries': [
- '-l<(android_stlport_library)',
+ '-l<(android_libcpp_library)',
+ '-latomic',
# Manually link the libgcc.a that the cross compiler uses.
'<!(<(android_toolchain)/*-gcc -print-libgcc-file-name)',
'-lc',
@@ -4772,6 +4788,11 @@
],
}],
['clang==1', {
+ 'libraries!': [
+ # Clang with libc++ does not require an explicit atomic
+ # library reference.
+ '-latomic',
+ ],
'cflags': [
# Work around incompatibilities between bionic and clang
# headers.
@@ -5119,6 +5140,22 @@
}],
],
},
+ 'configurations': {
+ 'Release_Base': {
+ 'conditions': [
+ ['branding=="Chrome" and buildtype=="Official"', {
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ # The Google Chrome Framework dSYM generated by dsymutil has
+ # grown larger than 4GB, which dsymutil can't handle. Reduce
+ # the amount of debug symbols.
+ '-fno-standalone-debug', # See http://crbug.com/479841
+ ]
+ },
+ }],
+ ],
+ }, # configuration "Release"
+ }, # configurations
'xcode_settings': {
'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic
# (Equivalent to -fPIC)
@@ -5136,16 +5173,6 @@
# specified or not.
'-fno-strict-aliasing', # See http://crbug.com/32204.
],
- 'conditions': [
- ['branding=="Chrome" and buildtype=="Official"', {
- 'OTHER_CFLAGS': [
- # The Google Chrome Framework dSYM generated by dsymutil has
- # grown larger than 4GB, which dsymutil can't handle. Reduce
- # the amount of debug symbols.
- '-gline-tables-only', # See http://crbug.com/479841
- ]
- }],
- ],
},
'target_conditions': [
['_type=="executable"', {
@@ -5769,13 +5796,20 @@
'AdditionalOptions': [
'-fsanitize-coverage=<(sanitizer_coverage)',
],
- 'defines': [
- 'SANITIZER_COVERAGE',
- ],
},
}],
],
},
+ 'conditions': [
+ ['sanitizer_coverage!=0', {
+ # TODO(asan/win): Move this down into the general
+ # win-target_defaults section once the 64-bit asan runtime
+ # exists. See crbug.com/345874.
+ 'defines': [
+ 'SANITIZER_COVERAGE',
+ ],
+ }],
+ ],
},
'x64_Base': {
'msvs_settings': {
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 22cb45a..1bd666b 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/allocator.gni")
+import("//build/config/chrome_build.gni")
import("//build/config/crypto.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 455ec0d..2274c0e 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -66,11 +66,13 @@
# Selects the desired build flavor. Official builds get additional
# processing to prepare for release. Normally you will want to develop and
# test with this flag off.
+ # TODO(brettw) move to chrome_build.gni when DEPS are updated.
is_official_build = false
# Select the desired branding flavor. False means normal Chromium branding,
# true means official Google Chrome branding (requires extra Google-internal
# resources).
+ # TODO(brettw) move to chrome_build.gni when DEPS are updated.
is_chrome_branded = false
# Compile for Address Sanitizer to find memory bugs.
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 77ee311..093e8b3 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -157,12 +157,12 @@
android_gdbserver =
"$android_ndk_root/prebuilt/$android_prebuilt_arch/gdbserver/gdbserver"
- # stlport stuff --------------------------------------------------------------
+ # libc++ stuff ---------------------------------------------------------------
if (component_mode == "shared_library") {
- android_stlport_library = "stlport_shared"
+ android_libcpp_library = "c++_shared"
} else {
- android_stlport_library = "stlport_static"
+ android_libcpp_library = "c++_static"
}
# ABI ------------------------------------------------------------------------
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 39b2f39..b1b23b0 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1555,8 +1555,8 @@
android_apk(target_name) {
final_apk_path = "$root_build_dir/${apk_name}_apk/${apk_name}-debug.apk"
java_files = [
- "//testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java",
- "//testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java",
+ "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java",
+ "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java",
]
android_manifest = "//testing/android/native_test/java/AndroidManifest.xml"
native_libs = [ unittests_binary ]
@@ -1566,6 +1566,7 @@
deps = [
"//base:base_java",
"//build/android/pylib/remote/device/dummy:remote_device_dummy_apk",
+ "//testing/android/appurify_support:appurify_support_java",
]
if (defined(invoker.deps)) {
deps += invoker.deps
diff --git a/build/config/chrome_build.gni b/build/config/chrome_build.gni
new file mode 100644
index 0000000..e2ff123
--- /dev/null
+++ b/build/config/chrome_build.gni
@@ -0,0 +1,22 @@
+# Copyright 2015 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.
+
+declare_args() {
+ # Selects the desired build flavor. Official builds get additional
+ # processing to prepare for release. Normally you will want to develop and
+ # test with this flag off.
+ # TODO(brettw) move here from BUILDCONFIG.gn when DEPS are updated.
+ #is_official_build = false
+
+ # Select the desired branding flavor. False means normal Chromium branding,
+ # true means official Google Chrome branding (requires extra Google-internal
+ # resources).
+ # TODO(brettw) move here from BUILDCONFIG.gn when DEPS are updated.
+ #is_chrome_branded = false
+
+ # Break chrome.dll into multple pieces based on process type. Only available
+ # on Windows.
+ # TODO(brettw) make this work. When it does, the declaration should be:
+ is_multi_dll_chrome = is_win && !is_component_build
+}
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn
index 3d96500..e79a7b9 100644
--- a/build/config/clang/BUILD.gn
+++ b/build/config/clang/BUILD.gn
@@ -31,6 +31,16 @@
]
}
+ if (is_win) {
+ # Don't error on plugin warnings on Windows until pre-existing warnings
+ # are cleaned up. https://crbug.com/467287
+ cflags += [
+ "-Xclang",
+ "-plugin-arg-find-bad-constructs",
+ "-Xclang warn-only",
+ ]
+ }
+
cflags += [
"-Xclang",
"-add-plugin",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index c217154..ad94705 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/android/config.gni")
+import("//build/config/chrome_build.gni")
if (current_cpu == "arm") {
import("//build/config/arm.gni")
}
@@ -461,10 +462,10 @@
ldflags += [
"-Wl,--no-undefined",
- # Don't allow visible symbols from libgcc or stlport to be
+ # Don't allow visible symbols from libgcc or libc++ to be
# re-exported.
"-Wl,--exclude-libs=libgcc.a",
- "-Wl,--exclude-libs=libstlport_static.a",
+ "-Wl,--exclude-libs=libc++_static.a",
# Don't allow visible symbols from libraries that contain
# assembly code with symbols that aren't hidden properly.
@@ -546,7 +547,7 @@
]
}
- # Stlport setup. Android uses a different (smaller) version of the STL.
+ # Android standard library setup.
if (is_android) {
if (is_clang) {
# Work around incompatibilities between bionic and clang headers.
@@ -556,11 +557,7 @@
]
}
- defines += [
- "USE_STLPORT=1",
- "_STLP_USE_PTR_SPECIALIZATIONS=1",
- "__GNU_SOURCE=1", # Necessary for clone().
- ]
+ defines += [ "__GNU_SOURCE=1" ] # Necessary for clone().
# TODO(jdduke) Re-enable on mips after resolving linking
# issues with libc++ (crbug.com/456380).
@@ -569,45 +566,48 @@
}
ldflags += [ "-nostdlib" ]
- # NOTE: The stlport header include paths below are specified in cflags
+ # NOTE: The libc++ header include paths below are specified in cflags
# rather than include_dirs because they need to come after include_dirs.
# Think of them like system headers, but don't use '-isystem' because the
# arm-linux-androideabi-4.4.3 toolchain (circa Gingerbread) will exhibit
# strange errors. The include ordering here is important; change with
# caution.
- android_stlport_root = "$android_ndk_root/sources/cxx-stl/stlport"
+ android_libcpp_root = "$android_ndk_root/sources/cxx-stl/llvm-libc++"
- cflags += [ "-isystem" +
- rebase_path("$android_stlport_root/stlport", root_build_dir) ]
- lib_dirs += [ "$android_stlport_root/libs/$android_app_abi" ]
+ cflags += [
+ "-isystem" +
+ rebase_path("$android_libcpp_root/libcxx/include", root_build_dir),
+ "-isystem" + rebase_path(
+ "$android_ndk_root/sources/cxx-stl/llvm-libc++abi/libcxxabi/include",
+ root_build_dir),
+ "-isystem" +
+ rebase_path("$android_ndk_root/sources/android/support/include",
+ root_build_dir),
+ ]
+
+ lib_dirs += [ "$android_libcpp_root/libs/$android_app_abi" ]
if (component_mode == "shared_library") {
- libs += [ "stlport_shared" ]
+ android_libcpp_library = "c++_shared"
} else {
- libs += [ "stlport_static" ]
- }
-
- if (current_cpu == "mipsel") {
- libs += [
- # ld linker is used for mips Android, and ld does not accept library
- # absolute path prefixed by "-l"; Since libgcc does not exist in mips
- # sysroot the proper library will be linked.
- # TODO(gordanac): Remove once gold linker is used for mips Android.
- "gcc",
- ]
- } else {
- libs += [
- # Manually link the libgcc.a that the cross compiler uses. This is
- # absolute because the linker will look inside the sysroot if it's not.
- rebase_path(android_libgcc_file),
- ]
+ android_libcpp_library = "c++_static"
}
libs += [
+ "$android_libcpp_library",
+
+ # Manually link the libgcc.a that the cross compiler uses. This is
+ # absolute because the linker will look inside the sysroot if it's not.
+ rebase_path(android_libgcc_file),
"c",
"dl",
"m",
]
+
+ # Clang with libc++ does not require an explicit atomic library reference.
+ if (!is_clang) {
+ libs += [ "atomic" ]
+ }
}
}
diff --git a/build/config/features.gni b/build/config/features.gni
index dd7b081..290c1d6 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -11,6 +11,7 @@
#
# See also build/config/ui.gni
+import("//build/config/chrome_build.gni")
if (is_android) {
import("//build/config/android/config.gni")
}
@@ -32,8 +33,8 @@
# the commented out logic.
# Eventually we want this to be:
# enable_nacl = !is_ios && !is_android
- enable_nacl =
- (is_linux && !is_chromeos && !is_debug && current_cpu == "x64") || is_nacl
+ enable_nacl = (is_linux && !is_chromeos && !is_component_build &&
+ current_cpu == "x64") || is_nacl
enable_nacl_untrusted = enable_nacl
enable_pnacl = enable_nacl_untrusted
@@ -84,6 +85,20 @@
# Enables browser side Content Decryption Modules. Required for embedders
# (e.g. Android and ChromeCast) that use a browser side CDM.
enable_browser_cdms = is_android
+
+ # Variable safe_browsing is used to control the build time configuration for
+ # safe browsing feature. Safe browsing can be compiled in 3 different levels:
+ # 0 disables it, 1 enables it fully, and 2 enables only UI and reporting
+ # features without enabling phishing and malware detection. This is useful to
+ # integrate a third party phishing/malware detection to existing safe browsing
+ # logic.
+ if (is_android) {
+ safe_browsing_mode = 2
+ } else if (is_ios) {
+ safe_browsing_mode = 0
+ } else {
+ safe_browsing_mode = 1
+ }
}
# Additional dependent variables -----------------------------------------------
@@ -133,19 +148,6 @@
enable_extensions = !is_android && !is_ios
-# Variable safe_browsing is used to control the build time configuration for
-# safe browsing feature. Safe browsing can be compiled in 3 different levels: 0
-# disables it, 1 enables it fully, and 2 enables only UI and reporting features
-# without enabling phishing and malware detection. This is useful to integrate
-# a third party phishing/malware detection to existing safe browsing logic.
-if (is_android) {
- safe_browsing_mode = 2
-} else if (is_ios) {
- safe_browsing_mode = 0
-} else {
- safe_browsing_mode = 1
-}
-
enable_task_manager = !is_ios && !is_android
use_cups = is_desktop_linux || is_mac
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
index 44995a3..600085e 100644
--- a/build/config/mac/mac_sdk.gni
+++ b/build/config/mac/mac_sdk.gni
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chrome_build.gni")
+
declare_args() {
# Minimum supported version of the Mac SDK.
mac_sdk_min = "10.6"
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 63728d9..3972a5c 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -22,11 +22,18 @@
}
source_set("options_sources") {
- visibility = [ ":deps" ]
+ visibility = [
+ ":deps",
+ "//:gn_visibility",
+ ]
sources = [
"//build/sanitizers/sanitizer_options.cc",
]
+ if (is_asan) {
+ sources += [ "//build/sanitizers/asan_suppressions.cc" ]
+ }
+
if (is_tsan) {
sources += [ "//build/sanitizers/tsan_suppressions.cc" ]
}
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni
index 057971d..e5a9c2b 100644
--- a/build/config/sysroot.gni
+++ b/build/config/sysroot.gni
@@ -5,6 +5,8 @@
# This header file defines the "sysroot" variable which is the absolute path
# of the sysroot. If no sysroot applies, the variable will be an empty string.
+import("//build/config/chrome_build.gni")
+
declare_args() {
# The absolute path of the sysroot that is applied when compiling using
# the target toolchain.
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 58e7ff5..4257cc0 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -2,36 +2,40 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# This file defines three targets that we are using to
-# track the progress of the GYP->GN migration:
+# This file defines five targets that we are using to track the progress of the
+# GYP->GN migration:
#
-# If you run 'ninja gn_build gyp_remaining gyp_groups', and then
-# run 'ninja', the second ninja invocation should do nothing. This
-# indicates that everything built by a ninja build is in fact
-# listed in one of these targets.
+# 'both_gn_and_gyp' lists what GN is currently capable of building and should
+# match the 'both_gn_and_gyp' target in //BUILD.gn.
#
-# 'gn_all' lists what GN is currently capable of building and should
-# match the 'gn_all' target in //BUILD.gn.
+# 'gyp_all' Should include everything built when building "all"; i.e., if you
+# type 'ninja gyp_all' and then 'ninja all', the second build should do
+# nothing. 'gyp_all' should just depend on the other four targets.
+#
+# 'gyp_only' lists any targets that are not meant to be ported over to the GN
+# build.
#
# 'gyp_remaining' lists all of the targets that still need to be converted,
-# i.e., all of the other (non-empty) targets that a GYP build
-# will build.
+# i.e., all of the other (non-empty) targets that a GYP build will build.
#
-# 'gyp_groups' lists any empty (group) targets in the GYP build that
-# are not picked up by gn_all or gyp_remaining; this is a
-# separate target to ensure that when we build it, only
-# stamp targets file are we don't accidentally pick up something
-# not listed in one of the other two targets.
-#
-# TODO(GYP), TODO(dpranke) Add a build step to the bot that enforces the
-# above contracts.
+# TODO(GYP): crbug.com/481694. Add a build step to the bot that enforces the
+# above contracts.
{
'targets': [
{
- # This target should mirror the structure of //:gn_all
- # as closely as possible, for ease of comparison.
- 'target_name': 'gn_all',
+ 'target_name': 'gyp_all',
+ 'type': 'none',
+ 'dependencies': [
+ 'both_gn_and_gyp',
+ 'gyp_only',
+ 'gyp_remaining',
+ ]
+ },
+ {
+ # This target should mirror the structure of //:both_gn_and_gyp
+ # in src/BUILD.gn as closely as possible, for ease of comparison.
+ 'target_name': 'both_gn_and_gyp',
'type': 'none',
'dependencies': [
'../base/base.gyp:base_i18n_perftests',
@@ -98,6 +102,7 @@
'../media/media.gyp:ffmpeg_regression_tests', # TODO(GYP) this should be conditional on media_use_ffmpeg
'../media/media.gyp:media_perftests',
'../media/media.gyp:media_unittests',
+ '../media/midi/midi.gyp:midi_unittests',
'../media/cast/cast.gyp:cast_benchmarks',
'../media/cast/cast.gyp:cast_unittests',
'../media/cast/cast.gyp:generate_barcode_video',
@@ -197,6 +202,7 @@
'../ui/display/display.gyp:display_unittests',
'../ui/events/events.gyp:events_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
+ '../ui/gl/gl_tests.gyp:gl_unittests',
'../ui/message_center/message_center.gyp:message_center_unittests',
'../ui/snapshot/snapshot.gyp:snapshot_unittests',
'../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
@@ -460,6 +466,7 @@
['OS=="win"', {
'dependencies': [
'../base/base.gyp:pe_image_test',
+ '../chrome/chrome.gyp:crash_service',
'../chrome_elf/chrome_elf.gyp:chrome_elf_unittests',
'../chrome_elf/chrome_elf.gyp:dll_hash_main',
'../components/components.gyp:wifi_test',
@@ -521,6 +528,7 @@
'../gpu/gpu.gyp:gpu_unittests_run',
'../media/cast/cast.gyp:cast_unittests_run',
'../media/media.gyp:media_unittests_run',
+ '../media/midi/midi.gyp:midi_unittests_run',
'../net/net.gyp:net_unittests_run',
'../sql/sql.gyp:sql_unittests_run',
'../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests_run',
@@ -606,7 +614,6 @@
'../chrome/chrome.gyp:app_installer',
'../chrome/chrome.gyp:app_installer_unittests',
'../chrome/chrome.gyp:app_shim',
- '../chrome/chrome.gyp:crash_service',
'../chrome/chrome.gyp:gcapi_dll',
'../chrome/chrome.gyp:gcapi_test',
'../chrome/chrome.gyp:installer_util_unittests',
@@ -666,39 +673,6 @@
}],
],
},
- {
- # This target, when built, should cause no actual work
- # to be done, just update a bunch of stamp files.
- 'target_name': 'gyp_groups',
- 'type': 'none',
- 'dependencies': [
- 'All',
- 'blink_tests',
- 'chromium_builder_asan',
- 'chromium_builder_chromedriver',
- 'chromium_builder_perf',
- 'chromium_builder_tests',
- 'chromium_builder_webrtc',
- 'chromium_gpu_builder',
- 'chromium_gpu_debug_builder',
- ],
- 'conditions': [
- ['use_aura==1', {
- 'dependencies': [
- 'aura_builder',
- ]
- }],
- ['OS=="win"', {
- 'dependencies': [
- 'chromium_builder',
- 'chromium_builder_dbg_drmemory_win',
- 'chromium_builder_nacl_sdk',
- 'chromium_builder_lkgr_drmemory_win',
- 'chromium_builder_dbg_tsan_win',
- ],
- }],
- ],
- },
]
}
diff --git a/build/gyp_chromium b/build/gyp_chromium
index 4ed15ba..736062e 100755
--- a/build/gyp_chromium
+++ b/build/gyp_chromium
@@ -254,16 +254,18 @@
else:
args.append(os.path.join(script_dir, 'all.gyp'))
+ supplemental_includes = GetSupplementalFiles()
+ gyp_vars_dict = GetGypVars(supplemental_includes)
# There shouldn't be a circular dependency relationship between .gyp files,
# but in Chromium's .gyp files, on non-Mac platforms, circular relationships
# currently exist. The check for circular dependencies is currently
- # bypassed on other platforms, but is left enabled on the Mac, where a
- # violation of the rule causes Xcode to misbehave badly.
+ # bypassed on other platforms, but is left enabled on iOS, where a violation
+ # of the rule causes Xcode to misbehave badly.
# TODO(mark): Find and kill remaining circular dependencies, and remove this
# option. http://crbug.com/35878.
# TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the
# list.
- if sys.platform not in ('darwin',):
+ if gyp_vars_dict.get('OS') != 'ios':
args.append('--no-circular-check')
# We explicitly don't support the make gyp generator (crbug.com/348686). Be
@@ -285,9 +287,6 @@
if syntax_check and int(syntax_check):
args.append('--check')
- supplemental_includes = GetSupplementalFiles()
- gyp_vars_dict = GetGypVars(supplemental_includes)
-
# TODO(dmikurube): Remove these checks and messages after a while.
if ('linux_use_tcmalloc' in gyp_vars_dict or
'android_use_tcmalloc' in gyp_vars_dict):
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index 6473794..2a2d50b 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -73,11 +73,11 @@
fi
lsb_release=$(lsb_release --codename --short)
-ubuntu_codenames="(precise|trusty|utopic)"
+ubuntu_codenames="(precise|trusty|utopic|vivid)"
if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
if [[ ! $lsb_release =~ $ubuntu_codenames ]]; then
- echo "ERROR: Only Ubuntu 12.04 (precise), 14.04 (trusty) and " \
- "14.10 (utopic) are currently supported" >&2
+ echo "ERROR: Only Ubuntu 12.04 (precise), 14.04 (trusty), " \
+ "14.10 (utopic) and 15.04 (vivid) are currently supported" >&2
exit 1
fi
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index 18239b7..e25efbc 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -100,6 +100,7 @@
IDR_TOOLBAR_SHADOW_FULL_BLEED
IDR_TRANSLATE_JS
IDR_UBER_UTILS_JS
+IDR_WEBUI_CSS_TEXT_DEFAULTS
IDR_WEBUI_I18N_TEMPLATE_JS
IDR_WEBUI_I18N_TEMPLATE_POLYMER_JS
IDR_WEBUI_JSTEMPLATE_JS
diff --git a/build/isolate.gypi b/build/isolate.gypi
index 7b050e2..10033da 100644
--- a/build/isolate.gypi
+++ b/build/isolate.gypi
@@ -88,6 +88,7 @@
# once support for user-defined config variables is added.
'--config-variable',
'internal_gles2_conform_tests=<(internal_gles2_conform_tests)',
+ '--config-variable', 'kasko=<(kasko)',
'--config-variable', 'libpeer_target_type=<(libpeer_target_type)',
'--config-variable', 'lsan=<(lsan)',
'--config-variable', 'msan=<(msan)',
diff --git a/build/json_schema_api.gni b/build/json_schema_api.gni
index 68a9fdd..aa6365b 100644
--- a/build/json_schema_api.gni
+++ b/build/json_schema_api.gni
@@ -46,7 +46,10 @@
# If any deps are specified they will be inherited by the static library
# target.
#
-# The static library target also inherits the visibility and output_name
+# generate_static_library [optional, defaults to false]
+# Produces a static library instead of a source_set.
+#
+# The generated library target also inherits the visibility and output_name
# of its invoker.
template("json_schema_api") {
@@ -75,7 +78,6 @@
visibility = target_visibility
}
- sources = invoker.sources
root_namespace = invoker.root_namespace
compiler_root = "//tools/json_schema_compiler"
@@ -97,6 +99,7 @@
schema_generator_name = target_name + "_schema_generator"
action_foreach(schema_generator_name) {
script = compiler_script
+ sources = invoker.sources
inputs = compiler_sources
outputs = [
"$target_gen_dir/{{source_name_part}}.cc",
@@ -127,7 +130,7 @@
bundle_generator_schema_name = target_name + "_bundle_generator_schema"
action(bundle_generator_schema_name) {
script = compiler_script
- inputs = compiler_sources + sources + uncompiled_sources
+ inputs = compiler_sources + invoker.sources + uncompiled_sources
outputs = [
"$target_gen_dir/generated_schemas.cc",
"$target_gen_dir/generated_schemas.h",
@@ -138,7 +141,7 @@
"--namespace=$root_namespace",
"--generator=cpp-bundle-schema",
"--include-rules=$schema_include_rules",
- ] + rebase_path(sources, root_build_dir) +
+ ] + rebase_path(invoker.sources, root_build_dir) +
rebase_path(uncompiled_sources, root_build_dir)
}
}
@@ -157,7 +160,7 @@
target_name + "_bundle_generator_registration"
action(bundle_generator_registration_name) {
script = compiler_script
- inputs = compiler_sources + sources + uncompiled_sources
+ inputs = compiler_sources + invoker.sources + uncompiled_sources
outputs = [
"$root_gen_dir/$impl_dir/generated_api_registration.cc",
"$root_gen_dir/$impl_dir/generated_api_registration.h",
@@ -169,43 +172,69 @@
"--generator=cpp-bundle-registration",
"--impl-dir=" + rebase_path(impl_dir, "//"),
"--include-rules=$schema_include_rules",
- ] + rebase_path(sources, root_build_dir) +
+ ] + rebase_path(invoker.sources, root_build_dir) +
rebase_path(uncompiled_sources, root_build_dir)
}
}
- source_set(target_name) {
- sources = []
- deps = []
- public_deps = []
+ # Compute the contents of the library/source set.
+ lib_sources = invoker.sources
+ lib_deps = []
+ lib_public_deps = []
+ lib_extra_configs = []
- if (schemas) {
- sources += get_target_outputs(":$schema_generator_name")
- public_deps += [ ":$schema_generator_name" ]
- deps += [ "//tools/json_schema_compiler:generated_api_util" ]
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
- }
+ if (schemas) {
+ lib_sources += get_target_outputs(":$schema_generator_name")
+ lib_public_deps += [ ":$schema_generator_name" ]
+ lib_deps += [ "//tools/json_schema_compiler:generated_api_util" ]
+ lib_extra_configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+ }
- if (bundle) {
- sources += get_target_outputs(":$bundle_generator_schema_name")
- deps += [ ":$bundle_generator_schema_name" ]
- }
+ if (bundle) {
+ lib_sources += get_target_outputs(":$bundle_generator_schema_name")
+ lib_deps += [ ":$bundle_generator_schema_name" ]
+ }
- if (bundle_registration) {
- sources += get_target_outputs(":$bundle_generator_registration_name")
- deps += [ ":$bundle_generator_registration_name" ]
- }
+ if (bundle_registration) {
+ lib_sources += get_target_outputs(":$bundle_generator_registration_name")
+ lib_deps += [ ":$bundle_generator_registration_name" ]
+ }
- if (defined(invoker.deps)) {
- deps += invoker.deps
- }
- public_configs = [ ":$generated_config_name" ]
+ if (defined(invoker.deps)) {
+ lib_deps += invoker.deps
+ }
- if (defined(invoker.visibility)) {
- visibility = invoker.visibility
+ # Generate either a static library or a source set.
+ if (defined(invoker.generate_static_library) &&
+ invoker.generate_static_library) {
+ static_library(target_name) {
+ sources = lib_sources
+ deps = lib_deps
+ public_deps = lib_public_deps
+ configs += lib_extra_configs
+ public_configs = [ ":$generated_config_name" ]
+
+ if (defined(invoker.visibility)) {
+ visibility = invoker.visibility
+ }
+ if (defined(invoker.output_name)) {
+ output_name = invoker.output_name
+ }
}
- if (defined(invoker.output_name)) {
- output_name = invoker.output_name
+ } else {
+ source_set(target_name) {
+ sources = lib_sources
+ deps = lib_deps
+ public_deps = lib_public_deps
+ configs += lib_extra_configs
+ public_configs = [ ":$generated_config_name" ]
+
+ if (defined(invoker.visibility)) {
+ visibility = invoker.visibility
+ }
+ if (defined(invoker.output_name)) {
+ output_name = invoker.output_name
+ }
}
}
}
diff --git a/build/sanitizers/lsan_suppressions.cc b/build/sanitizers/lsan_suppressions.cc
index a076ba0..f9aae3e 100644
--- a/build/sanitizers/lsan_suppressions.cc
+++ b/build/sanitizers/lsan_suppressions.cc
@@ -66,6 +66,9 @@
"leak:gin/object_template_builder.h\n"
"leak:gin::internal::Dispatcher\n"
"leak:blink::LocalDOMWindow::getComputedStyle\n"
+// This should really be RemoteDOMWindow::create, but symbolization is
+// weird in release builds. https://crbug.com/484760
+"leak:blink::RemoteFrame::create\n"
// http://crbug.com/356785
"leak:content::RenderViewImplTest_DecideNavigationPolicyForWebUI_Test::TestBody\n"
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 352b41f..e053a16 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -157,6 +157,9 @@
"race:PrepareTextureMailbox\n"
"race:cc::LayerTreeHost::PaintLayerContents\n"
+// http://crbug.com/476529
+"deadlock:cc::VideoLayerImpl::WillDraw\n"
+
// http://crbug.com/328826
"race:gLCDOrder\n"
"race:gLCDOrientation\n"
@@ -295,9 +298,6 @@
// https://crbug.com/430533
"race:TileTaskGraphRunner::Run\n"
-// https://crbug.com/437044
-"race:SkEventTracer\n"
-
// https://crbug.com/448203
"race:blink::RemoteFrame::detach\n"
diff --git a/build/secondary/tools/grit/grit_rule.gni b/build/secondary/tools/grit/grit_rule.gni
index 09a04c1..35bbed3 100644
--- a/build/secondary/tools/grit/grit_rule.gni
+++ b/build/secondary/tools/grit/grit_rule.gni
@@ -75,6 +75,7 @@
# # You can also put deps here if the grit source depends on generated
# # files.
# }
+import("//build/config/chrome_build.gni")
import("//build/config/crypto.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 16034ea..df2b73a 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -157,7 +157,7 @@
RenderPassTextureSize(render_passes_in_draw_order[i])));
std::vector<RenderPassId> passes_to_delete;
- base::ScopedPtrHashMap<RenderPassId, ScopedResource>::const_iterator
+ base::ScopedPtrHashMap<RenderPassId, scoped_ptr<ScopedResource>>::const_iterator
pass_iter;
for (pass_iter = render_pass_textures_.begin();
pass_iter != render_pass_textures_.end();
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index e119d28..3a8d175 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -138,7 +138,7 @@
DrawingFrame* frame,
scoped_ptr<CopyOutputRequest> request) = 0;
- base::ScopedPtrHashMap<RenderPassId, ScopedResource> render_pass_textures_;
+ base::ScopedPtrHashMap<RenderPassId, scoped_ptr<ScopedResource>> render_pass_textures_;
OutputSurface* output_surface_;
ResourceProvider* resource_provider_;
scoped_ptr<OverlayProcessor> overlay_processor_;
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index 8ae3b04..1c4f431 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -86,7 +86,7 @@
ResourceProvider* provider_;
class RenderPassIdAllocator;
- typedef base::ScopedPtrHashMap<SurfaceId, RenderPassIdAllocator>
+ typedef base::ScopedPtrHashMap<SurfaceId, scoped_ptr<RenderPassIdAllocator>>
RenderPassIdAllocatorMap;
RenderPassIdAllocatorMap render_pass_allocator_map_;
int next_render_pass_id_;
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index b6b627f..afc0b81 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -68,8 +68,8 @@
SurfaceFactoryClient* client_;
SurfaceResourceHolder holder_;
- typedef base::ScopedPtrHashMap<SurfaceId, Surface> OwningSurfaceMap;
- base::ScopedPtrHashMap<SurfaceId, Surface> surface_map_;
+ typedef base::ScopedPtrHashMap<SurfaceId, scoped_ptr<Surface>> OwningSurfaceMap;
+ OwningSurfaceMap surface_map_;
DISALLOW_COPY_AND_ASSIGN(SurfaceFactory);
};
diff --git a/mojo/common/task_tracker.cc b/mojo/common/task_tracker.cc
index c0ffd3f..8665799 100644
--- a/mojo/common/task_tracker.cc
+++ b/mojo/common/task_tracker.cc
@@ -54,7 +54,6 @@
if (!birth_)
return false;
- tracked_objects::ThreadData::PrepareForStartOfRun(birth_);
(new (stopwatch()) tracked_objects::TaskStopwatch())->Start();
return true;
}
diff --git a/mojo/common/task_tracker_unittest.cc b/mojo/common/task_tracker_unittest.cc
index 77f7da8..090e586 100644
--- a/mojo/common/task_tracker_unittest.cc
+++ b/mojo/common/task_tracker_unittest.cc
@@ -15,7 +15,7 @@
public:
void SetUp() override {
tracked_objects::ThreadData::InitializeAndSetTrackingStatus(
- tracked_objects::ThreadData::PROFILING_CHILDREN_ACTIVE);
+ tracked_objects::ThreadData::PROFILING_ACTIVE);
}
void TearDown() override {
@@ -31,10 +31,10 @@
TaskTracker::EndTracking(id0);
tracked_objects::ProcessDataSnapshot snapshot;
- tracked_objects::ThreadData::Snapshot(&snapshot);
+ tracked_objects::ThreadData::Snapshot(0, &snapshot);
// Nested one is ignored.
- EXPECT_EQ(1U, snapshot.phased_process_data_snapshots[0].tasks.size());
+ EXPECT_EQ(1U, snapshot.phased_snapshots[0].tasks.size());
}
TEST_F(TaskTrackerTest, Twice) {
@@ -44,9 +44,9 @@
TaskTracker::EndTracking(id1);
tracked_objects::ProcessDataSnapshot snapshot;
- tracked_objects::ThreadData::Snapshot(&snapshot);
+ tracked_objects::ThreadData::Snapshot(0, &snapshot);
- EXPECT_EQ(2U, snapshot.phased_process_data_snapshots[0].tasks.size());
+ EXPECT_EQ(2U, snapshot.phased_snapshots[0].tasks.size());
}
} // namespace test
diff --git a/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc b/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc
index 95a7b5c..461b475 100644
--- a/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc
+++ b/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc
@@ -10,5 +10,5 @@
mojo::ViewManagerTestSuite test_suite(argc, argv);
return base::LaunchUnitTests(
- argc, argv, base::Bind(&TestSuite::Run, base::Unretained(&test_suite)));
+ argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
}
diff --git a/mojo/tests/task_tracker_perftest.cc b/mojo/tests/task_tracker_perftest.cc
index d728120..8183777 100644
--- a/mojo/tests/task_tracker_perftest.cc
+++ b/mojo/tests/task_tracker_perftest.cc
@@ -66,7 +66,7 @@
void SetUp() override {
tracked_objects::ThreadData::InitializeAndSetTrackingStatus(
- tracked_objects::ThreadData::PROFILING_CHILDREN_ACTIVE);
+ tracked_objects::ThreadData::PROFILING_ACTIVE);
}
void TearDown() override {
diff --git a/sandbox/linux/bpf_dsl/codegen.cc b/sandbox/linux/bpf_dsl/codegen.cc
index 99b78ed..bc2c7a2 100644
--- a/sandbox/linux/bpf_dsl/codegen.cc
+++ b/sandbox/linux/bpf_dsl/codegen.cc
@@ -131,7 +131,8 @@
CHECK_EQ(program_.size(), equivalent_.size());
Node res = program_.size();
- program_.push_back(sock_filter{code, jt, jf, k});
+ program_.push_back(sock_filter{
+ code, static_cast<uint8_t>(jt), static_cast<uint8_t>(jf), k});
equivalent_.push_back(res);
return res;
}
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
index d4d5280..f38232f 100644
--- a/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ b/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -22,6 +22,7 @@
#include "sandbox/linux/seccomp-bpf/errorcode.h"
#include "sandbox/linux/system_headers/linux_filter.h"
#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
namespace sandbox {
namespace bpf_dsl {
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
index 7f4866d..ca28c1d 100644
--- a/sandbox/linux/bpf_dsl/seccomp_macros.h
+++ b/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -11,7 +11,9 @@
// All x86_64 builds use a new enough bionic to have sys/user.h.
#if !defined(__BIONIC__) || defined(__x86_64__)
#include <sys/types.h> // Fix for gcc 4.7, make sure __uint16_t is defined.
+#if !defined(__native_client_nonsfi__)
#include <sys/user.h>
+#endif
#if defined(__mips__)
// sys/user.h in eglibc misses size_t definition
#include <stddef.h>
@@ -50,10 +52,10 @@
8*(nr) + 0)
-#if defined(__BIONIC__)
-// Old Bionic versions don't have sys/user.h, so we just define regs_struct
-// directly. This can be removed once we no longer need to support these old
-// Bionic versions.
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly. This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
struct regs_struct {
long int ebx;
long int ecx;
@@ -149,10 +151,10 @@
#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
8*(nr) + 0)
-#if defined(__BIONIC__)
-// Old Bionic versions don't have sys/user.h, so we just define regs_struct
-// directly. This can be removed once we no longer need to support these old
-// Bionic versions.
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly. This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
struct regs_struct {
unsigned long uregs[18];
};
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
index d449156..05250d1 100644
--- a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -188,12 +188,9 @@
static const char kSeccompKillError[] =
__FILE__":**CRASHING**:" SECCOMP_MESSAGE_KILL_CONTENT "\n";
WriteToStdErr(kSeccompKillError, sizeof(kSeccompKillError) - 1);
- // Make "request" volatile so that we can see it on the stack in a minidump.
- volatile uint64_t pid = args.args[0];
- volatile char* addr = reinterpret_cast<volatile char*>(pid & 0xFFF);
- *addr = '\0';
- // Hit the NULL page if this fails.
- addr = reinterpret_cast<volatile char*>(pid & 0xFFF);
+ // Make "pid" volatile so that we can see it on the stack in a minidump.
+ volatile uint64_t my_pid = sys_getpid();
+ volatile char* addr = reinterpret_cast<volatile char*>(my_pid & 0xFFF);
*addr = '\0';
for (;;)
_exit(1);
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 282e727..60c16d3 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -11,7 +11,6 @@
#include <sched.h>
#include <signal.h>
#include <stdint.h>
-#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/resource.h>
@@ -32,6 +31,11 @@
#include "sandbox/linux/system_headers/linux_futex.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
+// PNaCl toolchain does not provide sys/ioctl.h header.
+#if !defined(OS_NACL_NONSFI)
+#include <sys/ioctl.h>
+#endif
+
#if defined(OS_ANDROID)
#if !defined(F_DUPFD_CLOEXEC)
@@ -104,6 +108,7 @@
namespace sandbox {
+#if !defined(OS_NACL_NONSFI)
// Allow Glibc's and Android pthread creation flags, crash on any other
// thread creation attempts and EPERM attempts to use neither
// CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
@@ -261,21 +266,6 @@
.Else(CrashSIGSYS());
}
-ResultExpr RestrictClockID() {
- static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
- const Arg<clockid_t> clockid(0);
- return If(
-#if defined(OS_CHROMEOS)
- // Allow the special clock for Chrome OS used by Chrome tracing.
- clockid == base::TimeTicks::kClockSystemTrace ||
-#endif
- clockid == CLOCK_MONOTONIC ||
- clockid == CLOCK_PROCESS_CPUTIME_ID ||
- clockid == CLOCK_REALTIME ||
- clockid == CLOCK_THREAD_CPUTIME_ID,
- Allow()).Else(CrashSIGSYS());
-}
-
ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) {
switch (sysno) {
case __NR_sched_getaffinity:
@@ -306,5 +296,21 @@
const Arg<int> who(0);
return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS());
}
+#endif // !defined(OS_NACL_NONSFI)
+
+ResultExpr RestrictClockID() {
+ static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
+ const Arg<clockid_t> clockid(0);
+ return If(
+#if defined(OS_CHROMEOS)
+ // Allow the special clock for Chrome OS used by Chrome tracing.
+ clockid == base::TimeTicks::kClockSystemTrace ||
+#endif
+ clockid == CLOCK_MONOTONIC ||
+ clockid == CLOCK_PROCESS_CPUTIME_ID ||
+ clockid == CLOCK_REALTIME ||
+ clockid == CLOCK_THREAD_CPUTIME_ID,
+ Allow()).Else(CrashSIGSYS());
+}
} // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
index d557c5f..0ec396d 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -67,15 +67,6 @@
// |target_pid| while calling setpriority(2) / getpriority(2).
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid);
-// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime().
-// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
-// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID. In particular, this disallows
-// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those
-// returned by {clock,pthread}_getcpuclockid), which can leak information
-// about the state of the host OS.
-// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed.
-SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID();
-
// Restricts |pid| for sched_* syscalls which take a pid as the first argument.
// We only allow calling these syscalls if the pid argument is equal to the pid
// of the sandboxed process or 0 (indicating the current thread). The following
@@ -95,6 +86,15 @@
// process).
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetrusage();
+// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime().
+// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID. In particular, this disallows
+// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those
+// returned by {clock,pthread}_getcpuclockid), which can leak information
+// about the state of the host OS.
+// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID();
+
} // namespace sandbox.
#endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
index 3b3c8db..bc6461f 100644
--- a/sandbox/linux/seccomp-bpf/syscall.cc
+++ b/sandbox/linux/seccomp-bpf/syscall.cc
@@ -133,16 +133,21 @@
#else
".arm\n"
#endif
- "SyscallAsm:.fnstart\n"
+ "SyscallAsm:\n"
+#if !defined(__native_client_nonsfi__)
+ // .fnstart and .fnend pseudo operations creates unwind table.
+ // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which
+ // is not provided by PNaCl toolchain. Disable it.
+ ".fnstart\n"
+#endif
"@ args = 0, pretend = 0, frame = 8\n"
"@ frame_needed = 1, uses_anonymous_args = 0\n"
#if defined(__thumb__)
".cfi_startproc\n"
"push {r7, lr}\n"
+ ".save {r7, lr}\n"
".cfi_offset 14, -4\n"
".cfi_offset 7, -8\n"
- "mov r7, sp\n"
- ".cfi_def_cfa_register 7\n"
".cfi_def_cfa_offset 8\n"
#else
"stmfd sp!, {fp, lr}\n"
@@ -177,7 +182,11 @@
#else
"2:ldmfd sp!, {fp, pc}\n"
#endif
+#if !defined(__native_client_nonsfi__)
+ // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment,
+ // for more details.
".fnend\n"
+#endif
"9:.size SyscallAsm, 9b-SyscallAsm\n"
#elif defined(__mips__)
".text\n"
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc
index 79b7569..8f559e5 100644
--- a/sandbox/linux/seccomp-bpf/trap.cc
+++ b/sandbox/linux/seccomp-bpf/trap.cc
@@ -12,6 +12,7 @@
#include <algorithm>
#include <limits>
+#include "base/compiler_specific.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
@@ -121,15 +122,26 @@
}
void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) {
+ if (info) {
+ MSAN_UNPOISON(info, sizeof(*info));
+ }
+
+ // Obtain the signal context. This, most notably, gives us access to
+ // all CPU registers at the time of the signal.
+ ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+ if (ctx) {
+ MSAN_UNPOISON(ctx, sizeof(*ctx));
+ }
+
if (!global_trap_) {
RAW_SANDBOX_DIE(
"This can't happen. Found no global singleton instance "
"for Trap() handling.");
}
- global_trap_->SigSys(nr, info, void_context);
+ global_trap_->SigSys(nr, info, ctx);
}
-void Trap::SigSys(int nr, LinuxSigInfo* info, void* void_context) {
+void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) {
// Signal handlers should always preserve "errno". Otherwise, we could
// trigger really subtle bugs.
const int old_errno = errno;
@@ -137,7 +149,7 @@
// Various sanity checks to make sure we actually received a signal
// triggered by a BPF filter. If something else triggered SIGSYS
// (e.g. kill()), there is really nothing we can do with this signal.
- if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !void_context ||
+ if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !ctx ||
info->si_errno <= 0 ||
static_cast<size_t>(info->si_errno) > trap_array_size_) {
// ATI drivers seem to send SIGSYS, so this cannot be FATAL.
@@ -148,9 +160,6 @@
return;
}
- // Obtain the signal context. This, most notably, gives us access to
- // all CPU registers at the time of the signal.
- ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
// Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
// most versions of glibc don't include this information in siginfo_t. So,
diff --git a/sandbox/linux/seccomp-bpf/trap.h b/sandbox/linux/seccomp-bpf/trap.h
index bbddeb7..50ac3fd 100644
--- a/sandbox/linux/seccomp-bpf/trap.h
+++ b/sandbox/linux/seccomp-bpf/trap.h
@@ -61,7 +61,7 @@
// Make sure that SigSys is not inlined in order to get slightly better crash
// dumps.
- void SigSys(int nr, LinuxSigInfo* info, void* void_context)
+ void SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx)
__attribute__((noinline));
// We have a global singleton that handles all of our SIGSYS traps. This
// variable must never be deallocated after it has been set up initially, as
diff --git a/sandbox/linux/seccomp-bpf/trap_unittest.cc b/sandbox/linux/seccomp-bpf/trap_unittest.cc
index 3d95e34..99f94bf 100644
--- a/sandbox/linux/seccomp-bpf/trap_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/trap_unittest.cc
@@ -12,7 +12,6 @@
namespace sandbox {
namespace {
-#if !defined(THREAD_SANITIZER)
SANDBOX_TEST_ALLOW_NOISE(Trap, SigSysAction) {
// This creates a global Trap instance, and registers the signal handler
// (Trap::SigSysAction).
@@ -24,7 +23,6 @@
// "Unexpected SIGSYS received." so it is necessary to allow the noise.
raise(SIGSYS);
}
-#endif
} // namespace
} // namespace sandbox
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
index fdfcb94..264eb68 100644
--- a/sandbox/linux/services/syscall_wrappers.cc
+++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -148,24 +148,38 @@
sizeof(linux_value));
}
-#if defined(MEMORY_SANITIZER) || \
- (defined(ARCH_CPU_X86_64) && defined(__GNUC__) && !defined(__clang__))
-// If MEMORY_SANITIZER is enabled, it is necessary to call sigaction() here,
-// rather than the direct syscall (sys_sigaction() defined by ourselves).
-// It is because, if MEMORY_SANITIZER is enabled, sigaction is wrapped, and
-// |act->sa_handler| is injected in order to unpoisonize the memory passed via
-// callback's arguments. Please see msan_interceptors.cc for more details.
-// So, if the direct syscall is used, as MEMORY_SANITIZER does not know about
-// it, sigaction() invocation in other places would be broken (in more precise,
-// returned |oldact| would have a broken |sa_handler| callback).
+#if (defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
+ (defined(ARCH_CPU_X86_64) && !defined(__clang__))) && \
+ !defined(OS_NACL_NONSFI)
+// If MEMORY_SANITIZER or THREAD_SANITIZER is enabled, it is necessary to call
+// sigaction() here, rather than the direct syscall (sys_sigaction() defined
+// by ourselves).
+// It is because, if MEMORY_SANITIZER or THREAD_SANITIZER is enabled, sigaction
+// is wrapped, and |act->sa_handler| is injected in order to unpoisonize the
+// memory passed via callback's arguments for MEMORY_SANITIZER, or handle
+// signals to check thread consistency for THREAD_SANITIZER. Please see
+// msan_interceptors.cc and tsan_interceptors.cc for more details.
+// So, specifically, if MEMORY_SANITIZER is enabled while the direct syscall is
+// used, as MEMORY_SANITIZER does not know about it, sigaction() invocation in
+// other places would be broken (in more precise, returned |oldact| would have
+// a broken |sa_handler| callback).
// Practically, it would break NaCl's signal handler installation.
// cf) native_client/src/trusted/service_runtime/linux/nacl_signal.c.
+// As for THREAD_SANITIZER, the intercepted signal handlers are processed more
+// in other libc functions' interceptors (such as for raise()), so that it
+// would not work properly.
//
// Also on x86_64 architecture, we need naked function for rt_sigreturn.
// However, there is no simple way to define it with GCC. Note that the body
// of function is actually very small (only two instructions), but we need to
// define much debug information in addition, otherwise backtrace() used by
// base::StackTrace would not work so that some tests would fail.
+//
+// When this is built with PNaCl toolchain, we should always use sys_sigaction
+// below, because sigaction() provided by the toolchain is incompatible with
+// Linux's ABI. So, otherwise, it would just fail. Note that it is not
+// necessary to think about sigaction() invocation in other places even with
+// MEMORY_SANITIZER or THREAD_SANITIZER, because it would just fail there.
int sys_sigaction(int signum,
const struct sigaction* act,
struct sigaction* oldact) {
diff --git a/sandbox/linux/services/yama.cc b/sandbox/linux/services/yama.cc
index 6658160..151f4bd 100644
--- a/sandbox/linux/services/yama.cc
+++ b/sandbox/linux/services/yama.cc
@@ -10,7 +10,6 @@
#include <sys/types.h>
#include <unistd.h>
-#include "base/basictypes.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
diff --git a/sandbox/linux/system_headers/linux_futex.h b/sandbox/linux/system_headers/linux_futex.h
index 91733a8..4e28403 100644
--- a/sandbox/linux/system_headers/linux_futex.h
+++ b/sandbox/linux/system_headers/linux_futex.h
@@ -5,7 +5,9 @@
#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
+#if !defined(__native_client_nonsfi__)
#include <linux/futex.h>
+#endif // !defined(__native_client_nonsfi__)
#if !defined(FUTEX_WAIT)
#define FUTEX_WAIT 0
diff --git a/services/view_manager/animation_runner.h b/services/view_manager/animation_runner.h
index 64bf494..b79c680 100644
--- a/services/view_manager/animation_runner.h
+++ b/services/view_manager/animation_runner.h
@@ -86,7 +86,7 @@
};
using ViewToAnimationMap =
- base::ScopedPtrHashMap<ServerView*, ScheduledAnimationGroup>;
+ base::ScopedPtrHashMap<ServerView*, scoped_ptr<ScheduledAnimationGroup>>;
using IdToViewsMap = std::map<AnimationId, std::set<ServerView*>>;
void CancelAnimationForViewImpl(ServerView* view, CancelSource source);
diff --git a/services/window_manager/run_all_unittests.cc b/services/window_manager/run_all_unittests.cc
index 51fd967..f8f67b6 100644
--- a/services/window_manager/run_all_unittests.cc
+++ b/services/window_manager/run_all_unittests.cc
@@ -39,5 +39,5 @@
window_manager::WindowManagerTestSuite test_suite(argc, argv);
return base::LaunchUnitTests(
- argc, argv, base::Bind(&TestSuite::Run, base::Unretained(&test_suite)));
+ argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
}
diff --git a/sky/engine/web/tests/RunAllTests.cpp b/sky/engine/web/tests/RunAllTests.cpp
index 21048e9..0378d47 100644
--- a/sky/engine/web/tests/RunAllTests.cpp
+++ b/sky/engine/web/tests/RunAllTests.cpp
@@ -41,14 +41,14 @@
#include "sky/engine/public/web/Sky.h"
#include "sky/engine/testing/platform/platform_impl.h"
-int runHelper(TestSuite* testSuite) {
+int runHelper(base::TestSuite* testSuite) {
base::MessageLoopForUI message_loop;
blink::initialize(new sky::PlatformImpl());
return testSuite->Run();
}
int main(int argc, char** argv) {
- TestSuite test_suite(argc, argv);
+ base::TestSuite test_suite(argc, argv);
return base::LaunchUnitTests(
argc, argv, Bind(&runHelper, Unretained(&test_suite)));
}
diff --git a/testing/android/appurify_support.gyp b/testing/android/appurify_support.gyp
new file mode 100644
index 0000000..2904368
--- /dev/null
+++ b/testing/android/appurify_support.gyp
@@ -0,0 +1,22 @@
+# Copyright 2015 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.
+
+{
+ 'conditions': [
+ ['OS=="android"', {
+ 'targets': [
+ {
+ 'target_name': 'appurify_support_java',
+ 'type': 'none',
+ 'variables': {
+ 'java_in_dir': '../../testing/android/appurify_support/java',
+ },
+ 'includes': [
+ '../../build/java.gypi',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/testing/android/appurify_support/BUILD.gn b/testing/android/appurify_support/BUILD.gn
new file mode 100644
index 0000000..871f9d0
--- /dev/null
+++ b/testing/android/appurify_support/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2015 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.
+
+import("//build/config/android/rules.gni")
+
+# GYP: //testing/android/appurify_support.gyp:appurify_support_java
+android_library("appurify_support_java") {
+ chromium_code = true
+
+ java_files = [
+ "java/src/org/chromium/test/support/ResultsBundleGenerator.java",
+ "java/src/org/chromium/test/support/RobotiumBundleGenerator.java",
+ ]
+}
diff --git a/testing/android/appurify_support/java/src/org/chromium/test/support/ResultsBundleGenerator.java b/testing/android/appurify_support/java/src/org/chromium/test/support/ResultsBundleGenerator.java
new file mode 100644
index 0000000..c9588d9
--- /dev/null
+++ b/testing/android/appurify_support/java/src/org/chromium/test/support/ResultsBundleGenerator.java
@@ -0,0 +1,30 @@
+// Copyright 2015 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.test.support;
+
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Creates a results Bundle.
+ */
+public interface ResultsBundleGenerator {
+
+ /** Indicates the state of a test.
+ */
+ static enum TestResult {
+ PASSED, FAILED, ERROR, UNKNOWN
+ }
+
+ /** Creates a bundle of test results from the provided raw results.
+
+ Note: actual bundle content and format may vary.
+
+ @param rawResults A map between test names and test results.
+ */
+ Bundle generate(Map<String, TestResult> rawResults);
+}
+
diff --git a/testing/android/appurify_support/java/src/org/chromium/test/support/RobotiumBundleGenerator.java b/testing/android/appurify_support/java/src/org/chromium/test/support/RobotiumBundleGenerator.java
new file mode 100644
index 0000000..167e7b9
--- /dev/null
+++ b/testing/android/appurify_support/java/src/org/chromium/test/support/RobotiumBundleGenerator.java
@@ -0,0 +1,56 @@
+// Copyright 2015 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.test.support;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Map;
+
+/**
+ * Creates a results bundle that emulates the one created by Robotium.
+ */
+public class RobotiumBundleGenerator implements ResultsBundleGenerator {
+
+ private static final String TAG = "RobotiumBundleGenerator";
+
+ public Bundle generate(Map<String, ResultsBundleGenerator.TestResult> rawResults) {
+ int testsPassed = 0;
+ int testsFailed = 0;
+
+ for (Map.Entry<String, ResultsBundleGenerator.TestResult> entry : rawResults.entrySet()) {
+ switch (entry.getValue()) {
+ case PASSED:
+ ++testsPassed;
+ break;
+ case FAILED:
+ // TODO(jbudorick): Remove this log message once AMP execution and
+ // results handling has been stabilized.
+ Log.d(TAG, "FAILED: " + entry.getKey());
+ ++testsFailed;
+ break;
+ default:
+ Log.w(TAG, "Unhandled: " + entry.getKey() + ", "
+ + entry.getValue().toString());
+ break;
+ }
+ }
+
+ StringBuilder resultBuilder = new StringBuilder();
+ if (testsFailed > 0) {
+ resultBuilder.append(
+ "\nFAILURES!!! Tests run: " + Integer.toString(rawResults.size())
+ + ", Failures: " + Integer.toString(testsFailed) + ", Errors: 0");
+ } else {
+ resultBuilder.append("\nOK (" + Integer.toString(testsPassed) + " tests)");
+ }
+
+ Bundle resultsBundle = new Bundle();
+ resultsBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+ resultBuilder.toString());
+ return resultsBundle;
+ }
+}
diff --git a/testing/android/broker/BUILD.gn b/testing/android/broker/BUILD.gn
new file mode 100644
index 0000000..8daa040
--- /dev/null
+++ b/testing/android/broker/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2015 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.
+
+import("//build/config/android/rules.gni")
+
+# GYP: //testing/android/on_device_instrumentation.gyp:broker_java
+android_library("broker_java") {
+ chromium_code = true
+
+ java_files =
+ [ "java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java" ]
+}
diff --git a/testing/android/broker/java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java b/testing/android/broker/java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java
new file mode 100644
index 0000000..cd755d0
--- /dev/null
+++ b/testing/android/broker/java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java
@@ -0,0 +1,64 @@
+// Copyright 2015 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.test.broker;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * An Activity target for OnDeviceInstrumentationDriver that starts the specified
+ * Instrumentation test.
+ */
+public class OnDeviceInstrumentationBroker extends Activity {
+
+ public static final String EXTRA_INSTRUMENTATION_PACKAGE =
+ "org.chromium.test.broker.OnDeviceInstrumentationBroker."
+ + "InstrumentationPackage";
+ public static final String EXTRA_INSTRUMENTATION_CLASS =
+ "org.chromium.test.broker.OnDeviceInstrumentationBroker."
+ + "InstrumentationClass";
+ public static final String EXTRA_TARGET_ARGS =
+ "org.chromium.test.broker.OnDeviceInstrumentationBroker.TargetArgs";
+ public static final String EXTRA_TEST =
+ "org.chromium.test.broker.OnDeviceInstrumentationBroker.Test";
+
+ private static final String TAG = "OnDeviceInstrumentationBroker";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.d(TAG, "onCreate()");
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ Intent i = getIntent();
+ String instrumentationPackage = i.getStringExtra(EXTRA_INSTRUMENTATION_PACKAGE);
+ String instrumentationClass = i.getStringExtra(EXTRA_INSTRUMENTATION_CLASS);
+ Bundle targetArgs = i.getBundleExtra(EXTRA_TARGET_ARGS);
+ String test = i.getStringExtra(EXTRA_TEST);
+
+ if (instrumentationPackage == null || instrumentationClass == null) {
+ finish();
+ return;
+ }
+
+ ComponentName instrumentationComponent =
+ new ComponentName(instrumentationPackage, instrumentationClass);
+
+ if (test != null) {
+ targetArgs.putString("class", test);
+ }
+
+ startInstrumentation(instrumentationComponent, null, targetArgs);
+ finish();
+ }
+}
+
diff --git a/testing/android/driver/BUILD.gn b/testing/android/driver/BUILD.gn
new file mode 100644
index 0000000..436ac63
--- /dev/null
+++ b/testing/android/driver/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2015 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.
+
+import("//build/config/android/rules.gni")
+
+# GYP: //testing/android/on_device_instrumentation.gyp:driver_apk
+android_apk("driver_apk") {
+ android_manifest = "java/AndroidManifest.xml"
+ apk_name = "OnDeviceInstrumentationDriver"
+ testonly = true
+
+ deps = [
+ "//testing/android/appurify_support:appurify_support_java",
+ "//testing/android/broker:broker_java",
+ "//testing/android/reporter:reporter_java",
+ ]
+
+ java_files =
+ [ "java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java" ]
+}
diff --git a/testing/android/driver/java/AndroidManifest.xml b/testing/android/driver/java/AndroidManifest.xml
new file mode 100644
index 0000000..c7e99ef
--- /dev/null
+++ b/testing/android/driver/java/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2015 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.chromium.test.driver"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
+
+ <application android:label="OnDeviceInstrumentationDriver" />
+
+ <instrumentation android:name="org.chromium.test.driver.OnDeviceInstrumentationDriver"
+ android:targetPackage="org.chromium.test.driver"
+ android:label="OnDeviceInstrumentationDriver"/>
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+</manifest>
diff --git a/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java b/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java
new file mode 100644
index 0000000..78c571a
--- /dev/null
+++ b/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java
@@ -0,0 +1,271 @@
+// Copyright 2015 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.test.driver;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import org.chromium.test.broker.OnDeviceInstrumentationBroker;
+import org.chromium.test.reporter.TestStatusReceiver;
+import org.chromium.test.reporter.TestStatusReporter;
+import org.chromium.test.support.ResultsBundleGenerator;
+import org.chromium.test.support.RobotiumBundleGenerator;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * An Instrumentation that drives instrumentation tests from outside the app.
+ */
+public class OnDeviceInstrumentationDriver extends Instrumentation {
+
+ private static final String TAG = "OnDeviceInstrumentationDriver";
+
+ private static final String EXTRA_TEST_LIST =
+ "org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList";
+ private static final String EXTRA_TEST_LIST_FILE =
+ "org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile";
+ private static final String EXTRA_TARGET_PACKAGE =
+ "org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage";
+ private static final String EXTRA_TARGET_CLASS =
+ "org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass";
+
+ private static final Pattern COMMA = Pattern.compile(",");
+ private static final int TEST_WAIT_TIMEOUT = 5 * TestStatusReporter.HEARTBEAT_INTERVAL_MS;
+
+ private boolean mDriverStarted;
+ private Thread mDriverThread;
+ private Bundle mTargetArgs;
+ private String mTargetClass;
+ private String mTargetPackage;
+ private List<String> mTestClasses;
+
+ /** Parse any arguments and prepare to run tests.
+
+ @param arguments The arguments to parse.
+ */
+ @Override
+ public void onCreate(Bundle arguments) {
+ mTargetArgs = new Bundle(arguments);
+ mTargetPackage = arguments.getString(EXTRA_TARGET_PACKAGE);
+ if (mTargetPackage == null) {
+ fail("No target package.");
+ return;
+ }
+ mTargetArgs.remove(EXTRA_TARGET_PACKAGE);
+
+ mTargetClass = arguments.getString(EXTRA_TARGET_CLASS);
+ if (mTargetClass == null) {
+ fail("No target class.");
+ return;
+ }
+ mTargetArgs.remove(EXTRA_TARGET_CLASS);
+
+ mTestClasses = new ArrayList<String>();
+ String testList = arguments.getString(EXTRA_TEST_LIST);
+ if (testList != null) {
+ mTestClasses.addAll(Arrays.asList(COMMA.split(testList)));
+ mTargetArgs.remove(EXTRA_TEST_LIST);
+ }
+
+ String testListFilePath = arguments.getString(EXTRA_TEST_LIST_FILE);
+ if (testListFilePath != null) {
+ File testListFile = new File(Environment.getExternalStorageDirectory(),
+ testListFilePath);
+ try {
+ BufferedReader testListFileReader =
+ new BufferedReader(new FileReader(testListFile));
+ String test;
+ while ((test = testListFileReader.readLine()) != null) {
+ mTestClasses.add(test);
+ }
+ testListFileReader.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading " + testListFile.getAbsolutePath(), e);
+ }
+ mTargetArgs.remove(EXTRA_TEST_LIST_FILE);
+ }
+
+ if (mTestClasses.isEmpty()) {
+ fail("No tests.");
+ return;
+ }
+
+ mDriverThread = new Thread(
+ new Driver(mTargetPackage, mTargetClass, mTargetArgs, mTestClasses));
+
+ start();
+ }
+
+ /** Start running tests. */
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ // Start the driver on its own thread s.t. it can block while the main thread's
+ // Looper receives and handles messages.
+ if (!mDriverStarted) {
+ mDriverThread.start();
+ mDriverStarted = true;
+ }
+ }
+
+ /** Clean up the reporting service. */
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ private class Driver implements Runnable {
+
+ private static final String TAG = OnDeviceInstrumentationDriver.TAG + ".Driver";
+
+ private Bundle mTargetArgs;
+ private String mTargetClass;
+ private String mTargetPackage;
+ private List<String> mTestClasses;
+
+ public Driver(String targetPackage, String targetClass, Bundle targetArgs,
+ List<String> testClasses) {
+ mTargetPackage = targetPackage;
+ mTargetClass = targetClass;
+ mTargetArgs = targetArgs;
+ mTestClasses = testClasses;
+ }
+
+ private void sendTestStatus(int status, String testClass, String testMethod) {
+ Bundle statusBundle = new Bundle();
+ statusBundle.putString(InstrumentationTestRunner.REPORT_KEY_NAME_CLASS, testClass);
+ statusBundle.putString(InstrumentationTestRunner.REPORT_KEY_NAME_TEST, testMethod);
+ sendStatus(status, statusBundle);
+ }
+
+ /** Run the tests. */
+ @Override
+ public void run() {
+ final HashMap<String, ResultsBundleGenerator.TestResult> finished =
+ new HashMap<String, ResultsBundleGenerator.TestResult>();
+ final Object statusLock = new Object();
+
+ try {
+ TestStatusReceiver r = new TestStatusReceiver();
+ r.registerCallback(new TestStatusReceiver.StartCallback() {
+ @Override
+ public void testStarted(String testClass, String testMethod) {
+ sendTestStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_START,
+ testClass, testMethod);
+ synchronized (statusLock) {
+ statusLock.notify();
+ }
+ }
+ });
+ r.registerCallback(new TestStatusReceiver.PassCallback() {
+ @Override
+ public void testPassed(String testClass, String testMethod) {
+ sendTestStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_OK, testClass,
+ testMethod);
+ synchronized (statusLock) {
+ finished.put(testClass + "#" + testMethod,
+ ResultsBundleGenerator.TestResult.PASSED);
+ statusLock.notify();
+ }
+ }
+ });
+ r.registerCallback(new TestStatusReceiver.FailCallback() {
+ @Override
+ public void testFailed(String testClass, String testMethod) {
+ sendTestStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_ERROR,
+ testClass, testMethod);
+ synchronized (statusLock) {
+ finished.put(testClass + "#" + testMethod,
+ ResultsBundleGenerator.TestResult.FAILED);
+ statusLock.notify();
+ }
+ }
+ });
+ r.registerCallback(new TestStatusReceiver.HeartbeatCallback() {
+ @Override
+ public void heartbeat() {
+ Log.i(TAG, "Heartbeat received.");
+ synchronized (statusLock) {
+ statusLock.notify();
+ }
+ }
+ });
+ r.register(getContext());
+
+ for (String t : mTestClasses) {
+ Intent slaveIntent = new Intent();
+ slaveIntent.setComponent(new ComponentName(
+ mTargetPackage, OnDeviceInstrumentationBroker.class.getName()));
+ slaveIntent.putExtra(
+ OnDeviceInstrumentationBroker.EXTRA_INSTRUMENTATION_PACKAGE,
+ mTargetPackage);
+ slaveIntent.putExtra(
+ OnDeviceInstrumentationBroker.EXTRA_INSTRUMENTATION_CLASS,
+ mTargetClass);
+ slaveIntent.putExtra(OnDeviceInstrumentationBroker.EXTRA_TEST, t);
+ slaveIntent.putExtra(OnDeviceInstrumentationBroker.EXTRA_TARGET_ARGS,
+ mTargetArgs);
+ slaveIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ getContext().startActivity(slaveIntent);
+
+ synchronized (statusLock) {
+ while (!finished.containsKey(t)) {
+ long waitStart = System.currentTimeMillis();
+ statusLock.wait(TEST_WAIT_TIMEOUT);
+ if (System.currentTimeMillis() - waitStart > TEST_WAIT_TIMEOUT) {
+ Log.e(TAG, t + " has gone missing and is assumed to be dead.");
+ finished.put(t, ResultsBundleGenerator.TestResult.FAILED);
+ break;
+ }
+ }
+ }
+ }
+ getContext().unregisterReceiver(r);
+
+ } catch (InterruptedException e) {
+ fail("Interrupted while running tests.", e);
+ return;
+ }
+ pass(new RobotiumBundleGenerator().generate(finished));
+ }
+
+ }
+
+ private void fail(String reason) {
+ Log.e(TAG, reason);
+ failImpl(reason);
+ }
+
+ private void fail(String reason, Exception e) {
+ Log.e(TAG, reason, e);
+ failImpl(reason);
+ }
+
+ private void failImpl(String reason) {
+ Bundle b = new Bundle();
+ b.putString("reason", reason);
+ finish(Activity.RESULT_CANCELED, b);
+ }
+
+ private void pass(Bundle results) {
+ finish(Activity.RESULT_OK, results);
+ }
+}
diff --git a/testing/android/native_test.gyp b/testing/android/native_test.gyp
index b26e01e..5993c43 100644
--- a/testing/android/native_test.gyp
+++ b/testing/android/native_test.gyp
@@ -30,7 +30,7 @@
'target_name': 'native_test_jni_headers',
'type': 'none',
'sources': [
- 'native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java'
+ 'native_test/java/src/org/chromium/native_test/NativeTestActivity.java'
],
'variables': {
'jni_gen_package': 'testing',
diff --git a/testing/android/native_test/BUILD.gn b/testing/android/native_test/BUILD.gn
index e0288f6..5df47fd 100644
--- a/testing/android/native_test/BUILD.gn
+++ b/testing/android/native_test/BUILD.gn
@@ -26,7 +26,7 @@
# GYP: //testing/android/native_test.gyp:native_test_jni_headers
generate_jni("native_test_jni_headers") {
sources = [
- "java/src/org/chromium/native_test/ChromeNativeTestActivity.java",
+ "java/src/org/chromium/native_test/NativeTestActivity.java",
]
jni_package = "testing"
}
diff --git a/testing/android/native_test/java/AndroidManifest.xml b/testing/android/native_test/java/AndroidManifest.xml
index 244f116..a92fb5f 100644
--- a/testing/android/native_test/java/AndroidManifest.xml
+++ b/testing/android/native_test/java/AndroidManifest.xml
@@ -19,10 +19,10 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <application android:label="ChromeNativeTests"
+ <application android:label="NativeTests"
android:name="org.chromium.base.BaseChromiumApplication">
- <activity android:name=".ChromeNativeTestActivity"
- android:label="ChromeNativeTest"
+ <activity android:name=".NativeTestActivity"
+ android:label="NativeTest"
android:configChanges="orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -31,7 +31,7 @@
</activity>
</application>
- <instrumentation android:name="org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner"
+ <instrumentation android:name="org.chromium.native_test.NativeTestInstrumentationTestRunner"
android:targetPackage="org.chromium.native_test"
android:label="Instrumentation entry point for org.chromium.native_test"/>
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java b/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java
deleted file mode 100644
index 4e1a067..0000000
--- a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright 2014 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.native_test;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Environment;
-import android.util.Log;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * An Instrumentation that runs tests based on ChromeNativeTestActivity.
- */
-public class ChromeNativeTestInstrumentationTestRunner extends Instrumentation {
- // TODO(jbudorick): Remove this extra when b/18981674 is fixed.
- public static final String EXTRA_ONLY_OUTPUT_FAILURES =
- "org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner."
- + "OnlyOutputFailures";
-
- private static final String TAG = "ChromeNativeTestInstrumentationTestRunner";
-
- private static final int ACCEPT_TIMEOUT_MS = 5000;
- private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]+) .*");
-
- private static interface ResultsBundleGenerator {
- public Bundle generate(Map<String, TestResult> rawResults);
- }
-
- private String mCommandLineFile;
- private String mCommandLineFlags;
- private File mStdoutFile;
- private Bundle mLogBundle;
- private ResultsBundleGenerator mBundleGenerator;
- private boolean mOnlyOutputFailures;
-
- @Override
- public void onCreate(Bundle arguments) {
- mCommandLineFile = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE);
- mCommandLineFlags = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS);
- try {
- mStdoutFile = File.createTempFile(
- ".temp_stdout_", ".txt", Environment.getExternalStorageDirectory());
- Log.i(TAG, "stdout file created: " + mStdoutFile.getAbsolutePath());
- } catch (IOException e) {
- Log.e(TAG, "Unable to create temporary stdout file." + e.toString());
- finish(Activity.RESULT_CANCELED, new Bundle());
- return;
- }
- mLogBundle = new Bundle();
- mBundleGenerator = new RobotiumBundleGenerator();
- mOnlyOutputFailures = arguments.containsKey(EXTRA_ONLY_OUTPUT_FAILURES);
- start();
- }
-
- @Override
- public void onStart() {
- super.onStart();
- Bundle results = runTests();
- finish(Activity.RESULT_OK, results);
- }
-
- /** Runs the tests in the ChromeNativeTestActivity and returns a Bundle containing the results.
- */
- private Bundle runTests() {
- Log.i(TAG, "Creating activity.");
- Activity activityUnderTest = startNativeTestActivity();
-
- Log.i(TAG, "Waiting for tests to finish.");
- try {
- while (!activityUnderTest.isFinishing()) {
- Thread.sleep(100);
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for activity to be destroyed: " + e.toString());
- }
-
- Log.i(TAG, "Getting results.");
- Map<String, TestResult> results = parseResults(activityUnderTest);
-
- Log.i(TAG, "Parsing results and generating output.");
- return mBundleGenerator.generate(results);
- }
-
- /** Starts the ChromeNativeTestActivty.
- */
- private Activity startNativeTestActivity() {
- Intent i = new Intent(Intent.ACTION_MAIN);
- i.setComponent(new ComponentName(
- "org.chromium.native_test",
- "org.chromium.native_test.ChromeNativeTestActivity"));
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (mCommandLineFile != null) {
- Log.i(TAG, "Passing command line file extra: " + mCommandLineFile);
- i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile);
- }
- if (mCommandLineFlags != null) {
- Log.i(TAG, "Passing command line flag extra: " + mCommandLineFlags);
- i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags);
- }
- i.putExtra(ChromeNativeTestActivity.EXTRA_STDOUT_FILE, mStdoutFile.getAbsolutePath());
- return startActivitySync(i);
- }
-
- private static enum TestResult {
- PASSED, FAILED, ERROR, UNKNOWN
- }
-
- /**
- * Generates a map between test names and test results from the instrumented Activity's
- * output.
- */
- private Map<String, TestResult> parseResults(Activity activityUnderTest) {
- Map<String, TestResult> results = new HashMap<String, TestResult>();
-
- BufferedReader r = null;
-
- try {
- if (mStdoutFile == null || !mStdoutFile.exists()) {
- Log.e(TAG, "Unable to find stdout file.");
- return results;
- }
-
- r = new BufferedReader(new InputStreamReader(
- new BufferedInputStream(new FileInputStream(mStdoutFile))));
-
- for (String l = r.readLine(); l != null && !l.equals("<<ScopedMainEntryLogger");
- l = r.readLine()) {
- Matcher m = RE_TEST_OUTPUT.matcher(l);
- boolean isFailure = false;
- if (m.matches()) {
- if (m.group(1).equals("RUN")) {
- results.put(m.group(2), TestResult.UNKNOWN);
- } else if (m.group(1).equals("FAILED")) {
- results.put(m.group(2), TestResult.FAILED);
- isFailure = true;
- mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
- sendStatus(0, mLogBundle);
- } else if (m.group(1).equals("OK")) {
- results.put(m.group(2), TestResult.PASSED);
- }
- }
-
- // TODO(jbudorick): mOnlyOutputFailures is a workaround for b/18981674. Remove it
- // once that issue is fixed.
- if (!mOnlyOutputFailures || isFailure) {
- mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
- sendStatus(0, mLogBundle);
- }
- Log.i(TAG, l);
- }
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Couldn't find stdout file file: " + e.toString());
- } catch (IOException e) {
- Log.e(TAG, "Error handling stdout file: " + e.toString());
- } finally {
- if (r != null) {
- try {
- r.close();
- } catch (IOException e) {
- Log.e(TAG, "Error while closing stdout reader.");
- }
- }
- if (mStdoutFile != null) {
- if (!mStdoutFile.delete()) {
- Log.e(TAG, "Unable to delete " + mStdoutFile.getAbsolutePath());
- }
- }
- }
- return results;
- }
-
- /**
- * Creates a results bundle that emulates the one created by Robotium.
- */
- private static class RobotiumBundleGenerator implements ResultsBundleGenerator {
- public Bundle generate(Map<String, TestResult> rawResults) {
- Bundle resultsBundle = new Bundle();
-
- int testsPassed = 0;
- int testsFailed = 0;
-
- for (Map.Entry<String, TestResult> entry : rawResults.entrySet()) {
- switch (entry.getValue()) {
- case PASSED:
- ++testsPassed;
- break;
- case FAILED:
- // TODO(jbudorick): Remove this log message once AMP execution and
- // results handling has been stabilized.
- Log.d(TAG, "FAILED: " + entry.getKey());
- ++testsFailed;
- break;
- default:
- Log.w(TAG, "Unhandled: " + entry.getKey() + ", "
- + entry.getValue().toString());
- break;
- }
- }
-
- StringBuilder resultBuilder = new StringBuilder();
- if (testsFailed > 0) {
- resultBuilder.append(
- "\nFAILURES!!! Tests run: " + Integer.toString(rawResults.size())
- + ", Failures: " + Integer.toString(testsFailed) + ", Errors: 0");
- } else {
- resultBuilder.append("\nOK (" + Integer.toString(testsPassed) + " tests)");
- }
- resultsBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
- resultBuilder.toString());
- return resultsBundle;
- }
- }
-
-}
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
similarity index 88%
rename from testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
rename to testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
index 4a74877..e8c4055 100644
--- a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
@@ -9,9 +9,9 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
-import android.util.Log;
import org.chromium.base.CommandLine;
+import org.chromium.base.Log;
import org.chromium.base.PathUtils;
import org.chromium.base.PowerMonitor;
import org.chromium.base.ResourceExtractor;
@@ -24,15 +24,15 @@
* Our tests need to go up to our own java classes, which is not possible using
* the native activity class loader.
*/
-public class ChromeNativeTestActivity extends Activity {
+public class NativeTestActivity extends Activity {
public static final String EXTRA_COMMAND_LINE_FILE =
- "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile";
+ "org.chromium.native_test.NativeTestActivity.CommandLineFile";
public static final String EXTRA_COMMAND_LINE_FLAGS =
- "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags";
+ "org.chromium.native_test.NativeTestActivity.CommandLineFlags";
public static final String EXTRA_STDOUT_FILE =
- "org.chromium.native_test.ChromeNativeTestActivity.StdoutFile";
+ "org.chromium.native_test.NativeTestActivity.StdoutFile";
- private static final String TAG = "ChromeNativeTestActivity";
+ private static final String TAG = Log.makeTag("native_test");
private static final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread";
// We post a delayed task to run tests so that we do not block onCreate().
private static final long RUN_TESTS_DELAY_IN_MS = 300;
@@ -88,7 +88,7 @@
commandLineFilePath = Environment.getExternalStorageDirectory() + "/"
+ commandLineFilePath;
}
- Log.i(TAG, "command line file path: " + commandLineFilePath);
+ Log.i(TAG, "command line file path: %s", commandLineFilePath);
}
String stdoutFilePath = getIntent().getStringExtra(EXTRA_STDOUT_FILE);
@@ -113,9 +113,9 @@
private void loadLibraries() {
for (String library : NativeLibraries.LIBRARIES) {
- Log.i(TAG, "loading: " + library);
+ Log.i(TAG, "loading: %s", library);
System.loadLibrary(library);
- Log.i(TAG, "loaded: " + library);
+ Log.i(TAG, "loaded: %s", library);
}
}
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java
new file mode 100644
index 0000000..c5a4443
--- /dev/null
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java
@@ -0,0 +1,185 @@
+// Copyright 2014 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.native_test;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+
+import org.chromium.base.Log;
+import org.chromium.test.support.ResultsBundleGenerator;
+import org.chromium.test.support.RobotiumBundleGenerator;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * An Instrumentation that runs tests based on NativeTestActivity.
+ */
+public class NativeTestInstrumentationTestRunner extends Instrumentation {
+ // TODO(jbudorick): Remove this extra when b/18981674 is fixed.
+ public static final String EXTRA_ONLY_OUTPUT_FAILURES =
+ "org.chromium.native_test.NativeTestInstrumentationTestRunner."
+ + "OnlyOutputFailures";
+
+ private static final String TAG = Log.makeTag("native_test");
+
+ private static final int ACCEPT_TIMEOUT_MS = 5000;
+ private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]+) .*");
+
+ private String mCommandLineFile;
+ private String mCommandLineFlags;
+ private File mStdoutFile;
+ private Bundle mLogBundle;
+ private ResultsBundleGenerator mBundleGenerator;
+ private boolean mOnlyOutputFailures;
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ mCommandLineFile = arguments.getString(NativeTestActivity.EXTRA_COMMAND_LINE_FILE);
+ mCommandLineFlags = arguments.getString(NativeTestActivity.EXTRA_COMMAND_LINE_FLAGS);
+ try {
+ mStdoutFile = File.createTempFile(
+ ".temp_stdout_", ".txt", Environment.getExternalStorageDirectory());
+ Log.i(TAG, "stdout file created: %s", mStdoutFile.getAbsolutePath());
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to create temporary stdout file.", e);
+ finish(Activity.RESULT_CANCELED, new Bundle());
+ return;
+ }
+ mLogBundle = new Bundle();
+ mBundleGenerator = new RobotiumBundleGenerator();
+ mOnlyOutputFailures = arguments.containsKey(EXTRA_ONLY_OUTPUT_FAILURES);
+ start();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ Bundle results = runTests();
+ finish(Activity.RESULT_OK, results);
+ }
+
+ /** Runs the tests in the NativeTestActivity and returns a Bundle containing the results.
+ */
+ private Bundle runTests() {
+ Log.i(TAG, "Creating activity.");
+ Activity activityUnderTest = startNativeTestActivity();
+
+ Log.i(TAG, "Waiting for tests to finish.");
+ try {
+ while (!activityUnderTest.isFinishing()) {
+ Thread.sleep(100);
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting for activity to be destroyed: ", e);
+ }
+
+ Log.i(TAG, "Getting results.");
+ Map<String, ResultsBundleGenerator.TestResult> results = parseResults(activityUnderTest);
+
+ Log.i(TAG, "Parsing results and generating output.");
+ return mBundleGenerator.generate(results);
+ }
+
+ /** Starts the NativeTestActivty.
+ */
+ private Activity startNativeTestActivity() {
+ Intent i = new Intent(Intent.ACTION_MAIN);
+ i.setComponent(new ComponentName(
+ "org.chromium.native_test",
+ "org.chromium.native_test.NativeTestActivity"));
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (mCommandLineFile != null) {
+ Log.i(TAG, "Passing command line file extra: %s", mCommandLineFile);
+ i.putExtra(NativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile);
+ }
+ if (mCommandLineFlags != null) {
+ Log.i(TAG, "Passing command line flag extra: %s", mCommandLineFlags);
+ i.putExtra(NativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags);
+ }
+ i.putExtra(NativeTestActivity.EXTRA_STDOUT_FILE, mStdoutFile.getAbsolutePath());
+ return startActivitySync(i);
+ }
+
+ /**
+ * Generates a map between test names and test results from the instrumented Activity's
+ * output.
+ */
+ private Map<String, ResultsBundleGenerator.TestResult> parseResults(
+ Activity activityUnderTest) {
+ Map<String, ResultsBundleGenerator.TestResult> results =
+ new HashMap<String, ResultsBundleGenerator.TestResult>();
+
+ BufferedReader r = null;
+
+ try {
+ if (mStdoutFile == null || !mStdoutFile.exists()) {
+ Log.e(TAG, "Unable to find stdout file.");
+ return results;
+ }
+
+ r = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(new FileInputStream(mStdoutFile))));
+
+ for (String l = r.readLine(); l != null && !l.equals("<<ScopedMainEntryLogger");
+ l = r.readLine()) {
+ Matcher m = RE_TEST_OUTPUT.matcher(l);
+ boolean isFailure = false;
+ if (m.matches()) {
+ if (m.group(1).equals("RUN")) {
+ results.put(m.group(2), ResultsBundleGenerator.TestResult.UNKNOWN);
+ } else if (m.group(1).equals("FAILED")) {
+ results.put(m.group(2), ResultsBundleGenerator.TestResult.FAILED);
+ isFailure = true;
+ mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
+ sendStatus(0, mLogBundle);
+ } else if (m.group(1).equals("OK")) {
+ results.put(m.group(2), ResultsBundleGenerator.TestResult.PASSED);
+ }
+ }
+
+ // TODO(jbudorick): mOnlyOutputFailures is a workaround for b/18981674. Remove it
+ // once that issue is fixed.
+ if (!mOnlyOutputFailures || isFailure) {
+ mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
+ sendStatus(0, mLogBundle);
+ }
+ Log.i(TAG, l);
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Couldn't find stdout file file: ", e);
+ } catch (IOException e) {
+ Log.e(TAG, "Error handling stdout file: ", e);
+ } finally {
+ if (r != null) {
+ try {
+ r.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Error while closing stdout reader.", e);
+ }
+ }
+ if (mStdoutFile != null) {
+ if (!mStdoutFile.delete()) {
+ Log.e(TAG, "Unable to delete %s", mStdoutFile.getAbsolutePath());
+ }
+ }
+ }
+ return results;
+ }
+
+}
diff --git a/testing/android/native_test/native_test_launcher.cc b/testing/android/native_test/native_test_launcher.cc
index 51edf36..d49ca11 100644
--- a/testing/android/native_test/native_test_launcher.cc
+++ b/testing/android/native_test/native_test_launcher.cc
@@ -25,7 +25,7 @@
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "gtest/gtest.h"
-#include "jni/ChromeNativeTestActivity_jni.h"
+#include "jni/NativeTestActivity_jni.h"
#include "testing/android/native_test/native_test_util.h"
using testing::native_test_util::ArgsToArgv;
diff --git a/testing/android/on_device_instrumentation.gyp b/testing/android/on_device_instrumentation.gyp
new file mode 100644
index 0000000..12e0f35
--- /dev/null
+++ b/testing/android/on_device_instrumentation.gyp
@@ -0,0 +1,79 @@
+# Copyright 2015 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.
+
+{
+ 'conditions': [
+ ['OS=="android"', {
+ 'variables' : {
+ 'driver_apk_name': 'OnDeviceInstrumentationDriver',
+ 'driver_apk_path': '<(PRODUCT_DIR)/apks/<(driver_apk_name).apk'
+ },
+ 'targets': [
+ {
+ 'target_name': 'reporter_java',
+ 'type': 'none',
+ 'dependencies': ['../../base/base.gyp:base_java'],
+ 'variables': {
+ 'java_in_dir': '../../testing/android/reporter/java',
+ },
+ 'includes': [
+ '../../build/java.gypi',
+ ],
+ },
+ {
+ 'target_name': 'broker_java',
+ 'type': 'none',
+ 'variables': {
+ 'java_in_dir': '../../testing/android/broker/java',
+ },
+ 'includes': [
+ '../../build/java.gypi',
+ ],
+ },
+ {
+ 'target_name': 'driver_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'broker_java',
+ 'reporter_java',
+ 'appurify_support.gyp:appurify_support_java',
+ ],
+ 'variables': {
+ 'apk_name': '<(driver_apk_name)',
+ 'final_apk_path': '<(driver_apk_path)',
+ 'java_in_dir': '../../testing/android/driver/java',
+ },
+ 'includes': [
+ '../../build/java_apk.gypi',
+ ],
+ },
+ {
+ # This emulates gn's datadeps fields, allowing other APKs to declare
+ # that they require that this APK be built without including the
+ # driver's code.
+ 'target_name': 'require_driver_apk',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'require_<(driver_apk_name)',
+ 'message': 'Making sure <(driver_apk_path) has been built.',
+ 'variables': {
+ 'required_file': '<(PRODUCT_DIR)/driver_apk/<(driver_apk_name).apk.required',
+ },
+ 'inputs': [
+ '<(driver_apk_path)',
+ ],
+ 'outputs': [
+ '<(required_file)',
+ ],
+ 'action': [
+ 'python', '../../build/android/gyp/touch.py', '<(required_file)',
+ ],
+ },
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/testing/android/reporter/BUILD.gn b/testing/android/reporter/BUILD.gn
new file mode 100644
index 0000000..7086a79
--- /dev/null
+++ b/testing/android/reporter/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2015 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.
+
+import("//build/config/android/rules.gni")
+
+# GYP: //testing/android/on_device_instrumentation.gyp:reporter_java
+android_library("reporter_java") {
+ chromium_code = true
+
+ deps = [
+ "//base:base_java",
+ ]
+ java_files = [
+ "java/src/org/chromium/test/reporter/TestStatusListener.java",
+ "java/src/org/chromium/test/reporter/TestStatusReceiver.java",
+ "java/src/org/chromium/test/reporter/TestStatusReporter.java",
+ ]
+}
diff --git a/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusListener.java b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusListener.java
new file mode 100644
index 0000000..6275418
--- /dev/null
+++ b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusListener.java
@@ -0,0 +1,78 @@
+// Copyright 2015 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.test.reporter;
+
+import android.content.Context;
+import android.util.Log;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+
+/**
+ * A TestListener that reports when tests start, pass, or fail.
+ */
+public class TestStatusListener implements TestListener {
+
+ private static final String TAG = "TestStatusListener";
+
+ private boolean mFailed;
+ private final TestStatusReporter mReporter;
+
+ public TestStatusListener(Context context) {
+ mReporter = new TestStatusReporter(context);
+ }
+
+ /** Called when an error has occurred while running a test.
+
+ Note that an error usually means a problem with the test or test harness, not with
+ the code under test.
+
+ @param test The test in which the error occurred.
+ @param t The exception that was raised.
+ */
+ @Override
+ public void addError(Test test, Throwable t) {
+ Log.e(TAG, "Error while running " + test.toString(), t);
+ mFailed = true;
+ }
+
+ /** Called when a test has failed.
+
+ @param test The test in which the failure occurred.
+ @param t The exception that was raised.
+ */
+ public void addFailure(Test test, AssertionFailedError e) {
+ Log.e(TAG, "Failure while running " + test.toString(), e);
+ mFailed = true;
+ }
+
+ /** Called when a test has started.
+ @param test The test that started.
+ */
+ @Override
+ public void startTest(Test test) {
+ mFailed = false;
+ TestCase testCase = (TestCase) test;
+ mReporter.startHeartbeat();
+ mReporter.testStarted(testCase.getClass().getName(), testCase.getName());
+ }
+
+ /** Called when a test has ended.
+ @param test The test that ended.
+ */
+ @Override
+ public void endTest(Test test) {
+ TestCase testCase = (TestCase) test;
+ if (mFailed) {
+ mReporter.testFailed(testCase.getClass().getName(), testCase.getName());
+ } else {
+ mReporter.testPassed(testCase.getClass().getName(), testCase.getName());
+ }
+ mReporter.stopHeartbeat();
+ }
+
+}
diff --git a/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReceiver.java b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReceiver.java
new file mode 100644
index 0000000..e4af9b6
--- /dev/null
+++ b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReceiver.java
@@ -0,0 +1,128 @@
+// Copyright 2015 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.test.reporter;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Receives test status broadcasts send from
+ {@link org.chromium.test.reporter.TestStatusReporter}.
+ */
+public class TestStatusReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "ResultReceiver";
+
+ private final List<FailCallback> mFailCallbacks = new ArrayList<FailCallback>();
+ private final List<HeartbeatCallback> mHeartbeatCallbacks = new ArrayList<HeartbeatCallback>();
+ private final List<PassCallback> mPassCallbacks = new ArrayList<PassCallback>();
+ private final List<StartCallback> mStartCallbacks = new ArrayList<StartCallback>();
+
+ /** An IntentFilter that matches the intents that this class can receive. */
+ private static final IntentFilter INTENT_FILTER;
+ static {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(TestStatusReporter.ACTION_HEARTBEAT);
+ filter.addAction(TestStatusReporter.ACTION_TEST_FAILED);
+ filter.addAction(TestStatusReporter.ACTION_TEST_PASSED);
+ filter.addAction(TestStatusReporter.ACTION_TEST_STARTED);
+ try {
+ filter.addDataType(TestStatusReporter.DATA_TYPE_HEARTBEAT);
+ filter.addDataType(TestStatusReporter.DATA_TYPE_RESULT);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ Log.wtf(TAG, "Invalid MIME type", e);
+ }
+ INTENT_FILTER = filter;
+ }
+
+ /** A callback used when a test has failed. */
+ public interface FailCallback {
+ void testFailed(String testClass, String testMethod);
+ }
+
+ /** A callback used when a heartbeat is received. */
+ public interface HeartbeatCallback {
+ void heartbeat();
+ }
+
+ /** A callback used when a test has passed. */
+ public interface PassCallback {
+ void testPassed(String testClass, String testMethod);
+ }
+
+ /** A callback used when a test has started. */
+ public interface StartCallback {
+ void testStarted(String testClass, String testMethod);
+ }
+
+ /** Register a callback for when a test has failed. */
+ public void registerCallback(FailCallback c) {
+ mFailCallbacks.add(c);
+ }
+
+ /** Register a callback for when a heartbeat is received. */
+ public void registerCallback(HeartbeatCallback c) {
+ mHeartbeatCallbacks.add(c);
+ }
+
+ /** Register a callback for when a test has passed. */
+ public void registerCallback(PassCallback c) {
+ mPassCallbacks.add(c);
+ }
+
+ /** Register a callback for when a test has started. */
+ public void registerCallback(StartCallback c) {
+ mStartCallbacks.add(c);
+ }
+
+ /** Register this receiver using the provided context. */
+ public void register(Context c) {
+ c.registerReceiver(this, INTENT_FILTER);
+ }
+
+ /** Receive a broadcast intent.
+ *
+ * @param context The Context in which the receiver is running.
+ * @param intent The intent received.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String testClass = intent.getStringExtra(TestStatusReporter.EXTRA_TEST_CLASS);
+ String testMethod = intent.getStringExtra(TestStatusReporter.EXTRA_TEST_METHOD);
+
+ switch (intent.getAction()) {
+ case TestStatusReporter.ACTION_TEST_STARTED:
+ for (StartCallback c : mStartCallbacks) {
+ c.testStarted(testClass, testMethod);
+ }
+ break;
+ case TestStatusReporter.ACTION_TEST_PASSED:
+ for (PassCallback c : mPassCallbacks) {
+ c.testPassed(testClass, testMethod);
+ }
+ break;
+ case TestStatusReporter.ACTION_TEST_FAILED:
+ for (FailCallback c : mFailCallbacks) {
+ c.testFailed(testClass, testMethod);
+ }
+ break;
+ case TestStatusReporter.ACTION_HEARTBEAT:
+ for (HeartbeatCallback c : mHeartbeatCallbacks) {
+ c.heartbeat();
+ }
+ break;
+ default:
+ Log.e(TAG, "Unrecognized intent received: " + intent.toString());
+ break;
+ }
+ }
+
+}
+
diff --git a/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReporter.java b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReporter.java
new file mode 100644
index 0000000..6ac7312
--- /dev/null
+++ b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReporter.java
@@ -0,0 +1,83 @@
+// Copyright 2015 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.test.reporter;
+
+import android.content.Context;
+import android.content.Intent;
+
+import org.chromium.base.ThreadUtils;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Broadcasts test status to any listening {@link org.chromium.test.reporter.TestStatusReceiver}.
+ */
+public class TestStatusReporter {
+
+ public static final String ACTION_HEARTBEAT =
+ "org.chromium.test.reporter.TestStatusReporter.HEARTBEAT";
+ public static final String ACTION_TEST_STARTED =
+ "org.chromium.test.reporter.TestStatusReporter.TEST_STARTED";
+ public static final String ACTION_TEST_PASSED =
+ "org.chromium.test.reporter.TestStatusReporter.TEST_PASSED";
+ public static final String ACTION_TEST_FAILED =
+ "org.chromium.test.reporter.TestStatusReporter.TEST_FAILED";
+ public static final String DATA_TYPE_HEARTBEAT = "org.chromium.test.reporter/heartbeat";
+ public static final String DATA_TYPE_RESULT = "org.chromium.test.reporter/result";
+ public static final String EXTRA_TEST_CLASS =
+ "org.chromium.test.reporter.TestStatusReporter.TEST_CLASS";
+ public static final String EXTRA_TEST_METHOD =
+ "org.chromium.test.reporter.TestStatusReporter.TEST_METHOD";
+
+ public static final int HEARTBEAT_INTERVAL_MS = 5000;
+
+ private final Context mContext;
+ private final AtomicBoolean mKeepBeating = new AtomicBoolean(false);
+
+ public TestStatusReporter(Context c) {
+ mContext = c;
+ }
+
+ public void startHeartbeat() {
+ mKeepBeating.set(true);
+ Runnable heartbeat = new Runnable() {
+ @Override
+ public void run() {
+ Intent i = new Intent(ACTION_HEARTBEAT);
+ i.setType(DATA_TYPE_HEARTBEAT);
+ mContext.sendBroadcast(i);
+ if (mKeepBeating.get()) {
+ ThreadUtils.postOnUiThreadDelayed(this, HEARTBEAT_INTERVAL_MS);
+ }
+ }
+ };
+ ThreadUtils.postOnUiThreadDelayed(heartbeat, HEARTBEAT_INTERVAL_MS);
+ }
+
+ public void testStarted(String testClass, String testMethod) {
+ sendBroadcast(testClass, testMethod, ACTION_TEST_STARTED);
+ }
+
+ public void testPassed(String testClass, String testMethod) {
+ sendBroadcast(testClass, testMethod, ACTION_TEST_PASSED);
+ }
+
+ public void testFailed(String testClass, String testMethod) {
+ sendBroadcast(testClass, testMethod, ACTION_TEST_FAILED);
+ }
+
+ public void stopHeartbeat() {
+ mKeepBeating.set(false);
+ }
+
+ private void sendBroadcast(String testClass, String testMethod, String action) {
+ Intent i = new Intent(action);
+ i.setType(DATA_TYPE_RESULT);
+ i.putExtra(EXTRA_TEST_CLASS, testClass);
+ i.putExtra(EXTRA_TEST_METHOD, testMethod);
+ mContext.sendBroadcast(i);
+ }
+
+}
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index e7df4ed..177b686 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -58,7 +58,51 @@
},
"Linux ChromiumOS GN (dbg)": {
"additional_compile_targets": [
- "net_unittests"
+ "accessibility_unittests",
+ "app_list_unittests",
+ "aura_unittests",
+ "browser_tests",
+ "cacheinvalidation_unittests",
+ "chromedriver_unittests",
+ "chromeos_unittests",
+ "content_unittests",
+ "crypto_unittests",
+ "dbus_unittests",
+ "device_unittests",
+ "display_unittests",
+ "events_unittests",
+ "extensions_browsertests",
+ "extensions_unittests",
+ "gcm_unit_tests",
+ "gfx_unittests",
+ "gn_unittests",
+ "google_apis_unittests",
+ "gpu_unittests",
+ "interactive_ui_tests",
+ "ipc_tests",
+ "jingle_unittests",
+ "media_unittests",
+ "mojo_common_unittests",
+ "mojo_public_bindings_unittests",
+ "mojo_public_environment_unittests",
+ "mojo_public_system_unittests",
+ "mojo_public_utility_unittests",
+ "mojo_system_unittests",
+ "net_unittests",
+ "ppapi_unittests",
+ "printing_unittests",
+ "remoting_unittests",
+ "sandbox_linux_unittests",
+ "skia_unittests",
+ "sql_unittests",
+ "sync_unit_tests",
+ "ui_base_unittests",
+ "ui_chromeos_unittests",
+ "ui_touch_selection_unittests",
+ "unit_tests",
+ "url_unittests",
+ "views_unittests",
+ "wm_unittests"
],
"gtest_tests": [
{
@@ -173,6 +217,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "nacl_loader_unittests"
},
{
@@ -358,6 +405,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "nacl_loader_unittests"
},
{
@@ -539,6 +589,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "nacl_loader_unittests"
},
{
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 3b3c8fe..2711337 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4,14 +4,14 @@
{
"args": [
"--enable-browser-side-navigation",
- "--gtest_filter=-BatteryMonitorImplTest.BatteryManagerDefaultValues:BatteryMonitorImplTest.BatteryManagerResolvePromise:BatteryMonitorImplTest.BatteryManagerWithEventListener:BookmarkletTest.DocumentWrite:BookmarkletTest.NonEmptyResult:BookmarkletTest.Redirect:BookmarkletTest.RedirectVoided:ChildProcessLauncherBrowserTest.ChildSpawnFail:CrossProcessFrameTreeBrowserTest.CreateCrossProcessSubframeProxies:CrossProcessFrameTreeBrowserTest.OriginSetOnCrossProcessNavigations:CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DatabaseTest.ReloadPage:DeviceInertialSensorBrowserTest.LightOneOffInfintyTest:DeviceInertialSensorBrowserTest.LightTest:DeviceInertialSensorBrowserTest.MotionNullTest:DeviceInertialSensorBrowserTest.MotionTest:DeviceInertialSensorBrowserTest.OrientationNullTest:DeviceInertialSensorBrowserTest.OrientationTest:DOMStorageBrowserTest.SanityCheck:DOMStorageBrowserTest.SanityCheckIncognito:DownloadContentTest.CancelAtFinalRename:DownloadContentTest.CancelAtRelease:DownloadContentTest.CancelInterruptedDownload:DownloadContentTest.CancelResumingDownload:DownloadContentTest.DownloadCancelled:DownloadContentTest.DownloadGZipWithNoContent:DownloadContentTest.DownloadOctetStream:DownloadContentTest.MultiDownload:DownloadContentTest.RemoveDownload:DownloadContentTest.RemoveResumingDownload:DownloadContentTest.ResumeInterruptedDownload:DownloadContentTest.ResumeInterruptedDownloadBadPrecondition:DownloadContentTest.ResumeInterruptedDownloadNoRange:DownloadContentTest.ResumeInterruptedDownloadNoVerifiers:DownloadContentTest.ResumeWithDeletedFile:DownloadContentTest.ResumeWithFileFinalRenameError:DownloadContentTest.ResumeWithFileInitError:DownloadContentTest.ResumeWithFileIntermediateRenameError:DownloadContentTest.ShutdownAtRelease:DownloadContentTest.ShutdownInProgress:File/MediaTest.VideoBearOpusOgg/0:File/MediaTest.VideoBearOpusWebm/0:File/MediaTest.VideoBearSilentTheora/0:File/MediaTest.VideoBearSilentWebm/0:File/MediaTest.VideoBearTheora/0:File/MediaTest.VideoBearWavAlaw/0:File/MediaTest.VideoBearWavMulaw/0:File/MediaTest.VideoBearWavPcm/0:File/MediaTest.VideoBearWavPcm192kHz/0:File/MediaTest.VideoBearWavPcm3kHz/0:File/MediaTest.VideoBearWebm/0:File/MediaTest.VideoTulipWebm/0:FileSystemBrowserTest.CreateTest:FileSystemBrowserTest.RequestTest:FileSystemBrowserTestWithLowQuota.QuotaTest:FrameTreeBrowserTest.FrameTreeAfterCrash:FrameTreeBrowserTest.SandboxFlagsSetForChildFrames:IndexedDBBrowserTest.BlobsCountAgainstQuota:IndexedDBBrowserTest.CallbackAccounting:IndexedDBBrowserTest.CanDeleteWhenOverQuotaTest:IndexedDBBrowserTest.ConnectionsClosedOnTabClose:IndexedDBBrowserTest.CursorPrefetch:IndexedDBBrowserTest.CursorTest:IndexedDBBrowserTest.CursorTestIncognito:IndexedDBBrowserTest.DatabaseTest:IndexedDBBrowserTest.DeleteCompactsBackingStore:IndexedDBBrowserTest.DeleteForOriginDeletesBlobs:IndexedDBBrowserTest.DiskFullOnCommit:IndexedDBBrowserTest.DoesntHangTest:IndexedDBBrowserTest.EmptyBlob:IndexedDBBrowserTest.ForceCloseEventTest:IndexedDBBrowserTest.IndexTest:IndexedDBBrowserTest.KeyPathTest:IndexedDBBrowserTest.KeyTypesTest:IndexedDBBrowserTest.LevelDBLogFileTest:IndexedDBBrowserTest.NullKeyPathPersistence:IndexedDBBrowserTest.ObjectStoreTest:IndexedDBBrowserTest.PRE_NullKeyPathPersistence:IndexedDBBrowserTest.PRE_PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.TransactionGetTest:IndexedDBBrowserTest.TransactionTest:IndexedDBBrowserTest.VersionChangeCrashResilience:IndexedDBBrowserTestSingleProcess.RenderThreadShutdownTest:IndexedDBBrowserTestWithCorruptLevelDB.DestroyTest:IndexedDBBrowserTestWithGCExposed.BlobDidAck:IndexedDBBrowserTestWithGCExposed.BlobDidAckPrefetch:IndexedDBBrowserTestWithGCExposed.DatabaseCallbacksTest:IndexedDBBrowserTestWithLowQuota.QuotaTest:IndexedDBBrowserTestWithMissingSSTFile.DestroyTest:IndexedDBBrowserTestWithVersion0Schema.MigrationTest:IndexedDBBrowserTestWithVersion123456Schema.DestroyTest:IndexedDBBrowserTestWithVersion987654SSVData.DestroyTest:ManifestBrowserTest.DummyManifest:ManifestBrowserTest.DynamicManifest:ManifestBrowserTest.ParseErrorManifest:ManifestBrowserTest.ParsingErrorsManifest:MediaCanPlayTypeTest.CodecSupportTest_Avc1Variants:MediaCanPlayTypeTest.CodecSupportTest_Avc3Variants:MediaCanPlayTypeTest.CodecSupportTest_AvcLevels:MediaCanPlayTypeTest.CodecSupportTest_HLS:MediaCanPlayTypeTest.CodecSupportTest_mp3:MediaCanPlayTypeTest.CodecSupportTest_mp4:MediaCanPlayTypeTest.CodecSupportTest_Mp4aVariants:MediaCanPlayTypeTest.CodecSupportTest_ogg:MediaCanPlayTypeTest.CodecSupportTest_wav:MediaCanPlayTypeTest.CodecSupportTest_webm:MediaTest.Navigate:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.CorrectLengthWithNewTabNavigatingFromWebUI:NavigationControllerBrowserTest.DontIgnoreBackAfterNavEntryLimit:NavigationControllerBrowserTest.ErrorPageReplacement:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.SubframeOnEmptyPage:OutOfProcessPPAPITest.InputEvent:OutOfProcessPPAPITest.MediaStreamAudioTrack:OutOfProcessPPAPITest.MediaStreamVideoTrack:RendererAccessibilityTest.AccessibilityMessagesQueueWhileSwappedOut:RenderFrameHostImplBrowserTest.IsFocused_AtLoad:RenderFrameHostImplBrowserTest.IsFocused_Widget:RenderFrameHostManagerTest.BackForwardNotStale:RenderFrameHostManagerTest.ClickLinkAfter204Error:RenderFrameHostManagerTest.DisownSubframeOpener:RenderFrameHostManagerTest.DontPreemptNavigationWithFrameTreeUpdate:RenderFrameHostManagerTest.ForceSwapAfterWebUIBindings:RenderFrameHostManagerTest.IgnoreRendererDebugURLsWhenCrashed:RenderFrameHostManagerTest.NoScriptAccessAfterSwapOut:RenderFrameHostManagerTest.RendererDebugURLsDontSwap:RenderFrameHostManagerTest.RestoreFileAccessForHistoryNavigation:RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation:RenderFrameHostManagerTest.ShowLoadingURLUntilSpoof:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.InsertCharacters:RenderViewImplTest.NavigateFrame:RenderViewImplTest.NavigationStartOverride:RenderViewImplTest.OnHandleKeyboardEvent:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.StaleNavigationsIgnored:RenderViewImplTest.TestBackForward:ResourceDispatcherHostBrowserTest.CrossSiteAfterCrash:ResourceDispatcherHostBrowserTest.CrossSiteNoUnloadOn204:ResourceFetcherTests.ResourceFetcher404:ResourceFetcherTests.ResourceFetcherDeletedInCallback:ResourceFetcherTests.ResourceFetcherDidFail:ResourceFetcherTests.ResourceFetcherDownload:ResourceFetcherTests.ResourceFetcherPost:ResourceFetcherTests.ResourceFetcherSetHeader:ResourceFetcherTests.ResourceFetcherTimeout:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.BasicBackForward:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FragmentBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.HistoryLength:SessionHistoryTest.JavascriptHistory:SessionHistoryTest.LocationChangeInSubframe:SessionHistoryTest.LocationReplace:SitePerProcessAccessibilityBrowserTest.CrossSiteIframeAccessibility:SitePerProcessBrowserTest.CleanupCrossSiteIframe:SitePerProcessBrowserTest.CompositorFrameSwapped:SitePerProcessBrowserTest.CreateProxiesForNewFrames:SitePerProcessBrowserTest.CrossSiteDidStopLoading:SitePerProcessBrowserTest.CrossSiteIframe:SitePerProcessBrowserTest.DynamicSandboxFlags:SitePerProcessBrowserTest.DynamicSandboxFlagsRemoteToLocal:SitePerProcessBrowserTest.KillingRendererClearsDescendantProxies:SitePerProcessBrowserTest.NavigateRemoteFrame:SitePerProcessBrowserTest.NavigateRemoteFrameToBlankAndDataURLs:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcessWithSubtree:SitePerProcessBrowserTest.NavigateWithSiblingRemoteFrame:SitePerProcessBrowserTest.OriginReplication:SitePerProcessBrowserTest.ProxyCreationSkipsSubtree:SitePerProcessBrowserTest.RFPHDestruction:SitePerProcessBrowserTest.RestrictFrameDetach:SitePerProcessBrowserTest.SandboxFlagsReplication:SitePerProcessBrowserTest.SubframePostMessage:SitePerProcessDevToolsBrowserTest.CrossSiteIframeAgentHost:SpeechRecognitionBrowserTest.OneShotRecognition:StatsTableBrowserTest.StartWithStatTable:TransitionBrowserTest.NormalNavigationNotDeferred:TransitionBrowserTest.TransitionNavigationDataIsCleared:TransitionBrowserTest.TransitionNavigationIsDeferred:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsImplBrowserTest.GetSizeForNewRenderView:WebContentsViewAuraTest.ScreenshotForSwappedOutRenderViews:WebUIMojoTest.EndToEndPing:WorkerTest.IncognitoSharedWorkers:WorkerTest.MultipleSharedWorkers:WorkerTest.MultipleWorkers:WorkerTest.PassMessagePortToSharedWorker:WorkerTest.PassMessagePortToSharedWorkerDontWaitForConnect:WorkerTest.SharedWorkerTlsClientAuth:WorkerTest.SingleSharedWorker:WorkerTest.SingleWorker:WorkerTest.WorkerTlsClientAuth"
+ "--gtest_filter=-BookmarkletTest.DocumentWrite:BookmarkletTest.NonEmptyResult:BookmarkletTest.Redirect:BookmarkletTest.RedirectVoided:ChildProcessLauncherBrowserTest.ChildSpawnFail:CrossProcessFrameTreeBrowserTest.CreateCrossProcessSubframeProxies:CrossProcessFrameTreeBrowserTest.OriginSetOnCrossProcessNavigations:CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DownloadContentTest.CancelAtFinalRename:DownloadContentTest.CancelAtRelease:DownloadContentTest.CancelInterruptedDownload:DownloadContentTest.CancelResumingDownload:DownloadContentTest.DownloadCancelled:DownloadContentTest.DownloadGZipWithNoContent:DownloadContentTest.DownloadOctetStream:DownloadContentTest.MultiDownload:DownloadContentTest.RemoveDownload:DownloadContentTest.RemoveResumingDownload:DownloadContentTest.ResumeInterruptedDownload:DownloadContentTest.ResumeInterruptedDownloadBadPrecondition:DownloadContentTest.ResumeInterruptedDownloadNoRange:DownloadContentTest.ResumeInterruptedDownloadNoVerifiers:DownloadContentTest.ResumeWithDeletedFile:DownloadContentTest.ResumeWithFileFinalRenameError:DownloadContentTest.ResumeWithFileInitError:DownloadContentTest.ResumeWithFileIntermediateRenameError:DownloadContentTest.ShutdownAtRelease:DownloadContentTest.ShutdownInProgress:FrameTreeBrowserTest.SandboxFlagsSetForChildFrames:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.ErrorPageReplacement:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.SubframeOnEmptyPage:RFHMProcessPerTabTest.BackFromWebUI:RenderFrameHostManagerTest.BackForwardNotStale:RenderFrameHostManagerTest.DisownOpener:RenderFrameHostManagerTest.DisownSubframeOpener:RenderFrameHostManagerTest.DontPreemptNavigationWithFrameTreeUpdate:RenderFrameHostManagerTest.NoScriptAccessAfterSwapOut:RenderFrameHostManagerTest.RendererDebugURLsDontSwap:RenderFrameHostManagerTest.ShowLoadingURLUntilSpoof:RenderFrameHostManagerTest.SwappedOutViewHasCorrectVisibilityState:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.NavigationStartOverride:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.StaleNavigationsIgnored:RenderViewImplTest.TestBackForward:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.BasicBackForward:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FragmentBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.HistoryLength:SessionHistoryTest.JavascriptHistory:SessionHistoryTest.LocationChangeInSubframe:SitePerProcessAccessibilityBrowserTest.CrossSiteIframeAccessibility:SitePerProcessBrowserTest.CleanupCrossSiteIframe:SitePerProcessBrowserTest.CompositorFrameSwapped:SitePerProcessBrowserTest.CreateProxiesForNewFrames:SitePerProcessBrowserTest.CrossSiteDidStopLoading:SitePerProcessBrowserTest.CrossSiteIframe:SitePerProcessBrowserTest.DynamicSandboxFlags:SitePerProcessBrowserTest.DynamicSandboxFlagsRemoteToLocal:SitePerProcessBrowserTest.KillingRendererClearsDescendantProxies:SitePerProcessBrowserTest.NavigateRemoteFrame:SitePerProcessBrowserTest.NavigateRemoteFrameToBlankAndDataURLs:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcessWithSubtree:SitePerProcessBrowserTest.NavigateWithSiblingRemoteFrame:SitePerProcessBrowserTest.NavigatingToKilledProcessRestoresAllProxies:SitePerProcessBrowserTest.OriginReplication:SitePerProcessBrowserTest.OriginUpdatesReachProxies:SitePerProcessBrowserTest.ProxyCreationSkipsSubtree:SitePerProcessBrowserTest.RFPHDestruction:SitePerProcessBrowserTest.RestrictFrameDetach:SitePerProcessBrowserTest.SandboxFlagsReplication:SitePerProcessBrowserTest.SubframePostMessage:SitePerProcessDevToolsBrowserTest.CrossSiteIframeAgentHost:TransitionBrowserTest.NormalNavigationNotDeferred:TransitionBrowserTest.TransitionNavigationDataIsCleared:TransitionBrowserTest.TransitionNavigationIsDeferred:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsImplBrowserTest.GetSizeForNewRenderView:WebContentsViewAuraTest.OverscrollScreenshot:WebContentsViewAuraTest.ReplaceStateReloadPushState:WebUIMojoTest.EndToEndPing:WorkerTest.IncognitoSharedWorkers"
],
"test": "content_browsertests"
},
{
"args": [
"--enable-browser-side-navigation",
- "--gtest_filter=-NavigationControllerTest.CopyRestoredStateAndNavigate:NavigationControllerTest.LoadURL_AbortDoesntCancelPending:NavigationControllerTest.LoadURL_IgnorePreemptsPending:NavigationControllerTest.ShowRendererURLAfterFailUntilModified:NavigationControllerTest.ShowRendererURLInNewTabUntilModified:RenderFrameHostManagerTest.CancelPendingProperlyDeletesOrSwaps:RenderFrameHostManagerTest.NavigateWithEarlyClose:RenderFrameHostManagerTest.PageDoesBackAndReload:RenderViewHostTest.ResetUnloadOnReload:ResourceDispatcherHostTest.TransferNavigationHtml:ResourceDispatcherHostTest.TransferNavigationText:ResourceDispatcherHostTest.TransferNavigationWithProcessCrash:ResourceDispatcherHostTest.TransferNavigationWithTwoRedirects:ResourceDispatcherHostTest.TransferTwoNavigationsHtml:WebContentsImplTest.ActiveContentsCountChangeBrowsingInstance:WebContentsImplTest.CrossSiteNavigationBackPreempted:WebContentsImplTest.CrossSiteNavigationPreempted:WebContentsImplTest.CrossSiteNotPreemptedDuringBeforeUnload:WebContentsImplTest.NoEarlyStop:WebContentsImplTest.ShowInterstitialCrashRendererThenGoBack:WebContentsImplTest.ShowInterstitialFromBrowserNewNavigationProceed:WebContentsImplTest.ShowInterstitialThenGoBack"
+ "--gtest_filter=-NavigationControllerTest.CopyRestoredStateAndNavigate:RenderFrameHostManagerTest.CancelPendingProperlyDeletesOrSwaps:RenderFrameHostManagerTest.PageDoesBackAndReload:RenderViewHostTest.ResetUnloadOnReload:ResourceDispatcherHostTest.TransferNavigationHtml:ResourceDispatcherHostTest.TransferNavigationText:ResourceDispatcherHostTest.TransferNavigationWithProcessCrash:ResourceDispatcherHostTest.TransferNavigationWithTwoRedirects:ResourceDispatcherHostTest.TransferTwoNavigationsHtml:WebContentsImplTest.CrossSiteNavigationBackPreempted:WebContentsImplTest.CrossSiteNotPreemptedDuringBeforeUnload:WebContentsImplTest.NoEarlyStop:WebContentsImplTest.ShowInterstitialCrashRendererThenGoBack:WebContentsImplTest.ShowInterstitialFromBrowserNewNavigationProceed:WebContentsImplTest.ShowInterstitialThenGoBack"
],
"test": "content_unittests"
}
@@ -53,6 +53,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "net_unittests"
},
{
@@ -138,6 +141,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "message_center_unittests"
},
{
@@ -306,6 +312,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -467,6 +476,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true,
"shards": 4
@@ -518,9 +530,15 @@
"test": "app_list_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "base_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "browser_tests"
},
{
@@ -539,12 +557,18 @@
"test": "components_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "content_browsertests"
},
{
"test": "content_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "crypto_unittests"
},
{
@@ -563,6 +587,9 @@
"test": "gpu_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "interactive_ui_tests"
},
{
@@ -578,6 +605,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -596,6 +626,9 @@
"test": "mojo_system_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "net_unittests"
},
{
@@ -626,6 +659,9 @@
"test": "ui_base_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "unit_tests"
},
{
@@ -656,9 +692,15 @@
"test": "app_list_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "base_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "browser_tests"
},
{
@@ -677,12 +719,18 @@
"test": "components_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "content_browsertests"
},
{
"test": "content_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "crypto_unittests"
},
{
@@ -701,6 +749,9 @@
"test": "gpu_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "interactive_ui_tests"
},
{
@@ -716,6 +767,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -734,6 +788,9 @@
"test": "mojo_system_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "net_unittests"
},
{
@@ -764,6 +821,9 @@
"test": "ui_base_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
"test": "unit_tests"
},
{
@@ -854,6 +914,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "net_unittests"
},
{
@@ -966,6 +1029,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "net_unittests"
},
{
@@ -1085,6 +1151,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -1210,6 +1279,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -1335,6 +1407,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -1460,6 +1535,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -1585,6 +1663,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -1710,6 +1791,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -1835,6 +1919,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -1987,6 +2074,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -2152,6 +2242,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -2323,6 +2416,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -2488,6 +2584,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -2571,7 +2670,7 @@
{
"args": [
"--site-per-process",
- "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
+ "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
],
"test": "browser_tests"
},
@@ -2601,7 +2700,7 @@
{
"args": [
"--site-per-process",
- "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
+ "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
],
"test": "browser_tests"
},
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 88acb35..2a54542 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -10,6 +10,10 @@
{
"name": "webview_licenses",
"script": "webview_licenses.py"
+ },
+ {
+ "name": "telemetry_perf_unittests",
+ "script": "telemetry_perf_unittests.py"
}
]
},
@@ -18,6 +22,10 @@
{
"name": "webview_licenses",
"script": "webview_licenses.py"
+ },
+ {
+ "name": "telemetry_perf_unittests",
+ "script": "telemetry_perf_unittests.py"
}
]
},
@@ -132,17 +140,13 @@
"gn_unittests",
"google_apis_unittests",
"gpu_unittests",
+ "html_viewer_unittests",
"interactive_ui_tests",
"ipc_mojo_unittests",
"ipc_tests",
"jingle_unittests",
+ "mandoline:all",
"media_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"nacl_loader_unittests",
"net_unittests",
"ppapi_unittests",
@@ -157,14 +161,11 @@
"ui_touch_selection_unittests",
"unit_tests",
"url_unittests",
+ "view_manager_service_unittests",
"views_unittests",
"wm_unittests"
],
- "gtest_tests": [
- {
- "test": "base_unittests"
- }
- ]
+ "gtest_tests": []
},
"Linux GN (dbg)": {
"additional_compile_targets": [
@@ -196,13 +197,8 @@
"ipc_mojo_unittests",
"ipc_tests",
"jingle_unittests",
+ "mandoline:all",
"media_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"net_unittests",
"ppapi_unittests",
"printing_unittests",
@@ -376,6 +372,12 @@
"test": "media_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -630,6 +632,12 @@
"test": "media_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -874,6 +882,12 @@
"test": "media_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 8883601..58a4df2 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -190,6 +190,12 @@
"test": "message_center_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -389,6 +395,12 @@
"test": "message_center_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -588,6 +600,12 @@
"test": "message_center_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -788,6 +806,12 @@
"test": "message_center_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index dc1a9d7..8b94908 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -103,6 +103,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -267,6 +270,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -427,6 +433,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index dcdfe7c..132f87b 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -91,6 +91,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true,
"shards": 4
@@ -266,6 +269,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "nacl_loader_unittests"
},
{
@@ -392,6 +398,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
@@ -496,6 +505,9 @@
"test": "media_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"swarming": {
"can_use_on_swarming_builders": true
},
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index f3ad4ca..3c71c4d 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -240,6 +240,15 @@
"scripts": [
{
"args": [
+ "angle_perftests",
+ "--test-launcher-print-test-stdio=always",
+ "--test-launcher-jobs=1"
+ ],
+ "name": "angle_perftests",
+ "script": "gtest_perf_test.py"
+ },
+ {
+ "args": [
"performance_browser_tests",
"--test-launcher-print-test-stdio=always",
"--gtest_filter=TabCapturePerformanceTest.*:CastV2PerformanceTest.*",
@@ -255,6 +264,15 @@
"scripts": [
{
"args": [
+ "angle_perftests",
+ "--test-launcher-print-test-stdio=always",
+ "--test-launcher-jobs=1"
+ ],
+ "name": "angle_perftests",
+ "script": "gtest_perf_test.py"
+ },
+ {
+ "args": [
"performance_browser_tests",
"--test-launcher-print-test-stdio=always",
"--gtest_filter=TabCapturePerformanceTest.*:CastV2PerformanceTest.*",
@@ -287,7 +305,6 @@
"args": [
"angle_perftests",
"--test-launcher-print-test-stdio=always",
- "--gtest_filter=DrawCallPerf*",
"--test-launcher-jobs=1"
],
"name": "angle_perftests",
@@ -337,18 +354,6 @@
]
},
"Win 8 Perf (2)": {
- "scripts": [
- {
- "args": [
- "performance_browser_tests",
- "--test-launcher-print-test-stdio=always",
- "--gtest_filter=TabCapturePerformanceTest.*:CastV2PerformanceTest.*",
- "--test-launcher-jobs=1",
- "--enable-gpu"
- ],
- "name": "performance_browser_tests",
- "script": "gtest_perf_test.py"
- }
- ]
+ "scripts": []
}
}
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json
index 5742add..e0bae2f 100644
--- a/testing/buildbot/chromium.webkit.json
+++ b/testing/buildbot/chromium.webkit.json
@@ -135,6 +135,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "nacl_loader_unittests"
},
{
@@ -310,6 +313,9 @@
"test": "message_center_unittests"
},
{
+ "test": "midi_unittests"
+ },
+ {
"test": "nacl_loader_unittests"
},
{
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index ca0ab23..f349a2e 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -130,6 +130,12 @@
"test": "media_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -371,6 +377,12 @@
"test": "message_center_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -500,14 +512,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
@@ -562,14 +569,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
@@ -749,6 +751,12 @@
"test": "message_center_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -977,6 +985,12 @@
"test": "media_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "mojo_common_unittests"
},
{
@@ -1131,14 +1145,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
@@ -1193,14 +1202,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
@@ -1362,6 +1366,12 @@
"test": "media_unittests"
},
{
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
"test": "nacl_loader_unittests"
},
{
diff --git a/testing/buildbot/chromium_memory_trybot.json b/testing/buildbot/chromium_memory_trybot.json
index c58d2de..f17cb08 100644
--- a/testing/buildbot/chromium_memory_trybot.json
+++ b/testing/buildbot/chromium_memory_trybot.json
@@ -85,6 +85,12 @@
},
{
"swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
+ {
+ "swarming": {
"can_use_on_swarming_builders": true,
"shards": 2
},
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json
index d42d551..68735d8 100644
--- a/testing/buildbot/chromium_trybot.json
+++ b/testing/buildbot/chromium_trybot.json
@@ -213,6 +213,12 @@
},
"test": "message_center_unittests"
},
+ {
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ },
+ "test": "midi_unittests"
+ },
"mojo_common_unittests",
"mojo_public_bindings_unittests",
"mojo_public_environment_unittests",
diff --git a/testing/buildbot/tryserver.blink.json b/testing/buildbot/tryserver.blink.json
index fe4d275..ce5481e 100644
--- a/testing/buildbot/tryserver.blink.json
+++ b/testing/buildbot/tryserver.blink.json
@@ -13,7 +13,6 @@
"browser_tests",
"cacheinvalidation_unittests",
"chromedriver_unittests",
- "chromeos_unittests",
"components_browsertests",
"components_unittests",
"content_browsertests",
@@ -49,7 +48,6 @@
"sql_unittests",
"sync_unit_tests",
"ui_base_unittests",
- "ui_chromeos_unittests",
"ui_touch_selection_unittests",
"unit_tests",
"url_unittests",
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json
index 6d3c6d4..f5a7f98 100644
--- a/testing/buildbot/tryserver.chromium.linux.json
+++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -13,7 +13,46 @@
},
"linux_chromium_gn_chromeos_dbg": {
"additional_compile_targets": [
- "net_unittests"
+ "accessibility_unittests",
+ "app_list_unittests",
+ "aura_unittests",
+ "browser_tests",
+ "cacheinvalidation_unittests",
+ "chromedriver_unittests",
+ "chromeos_unittests",
+ "content_unittests",
+ "crypto_unittests",
+ "dbus_unittests",
+ "device_unittests",
+ "display_unittests",
+ "events_unittests",
+ "extensions_browsertests",
+ "extensions_unittests",
+ "gcm_unit_tests",
+ "gfx_unittests",
+ "gn_unittests",
+ "google_apis_unittests",
+ "gpu_unittests",
+ "interactive_ui_tests",
+ "ipc_tests",
+ "jingle_unittests",
+ "mandoline:all",
+ "media_unittests",
+ "net_unittests",
+ "ppapi_unittests",
+ "printing_unittests",
+ "remoting_unittests",
+ "sandbox_linux_unittests",
+ "skia_unittests",
+ "sql_unittests",
+ "sync_unit_tests",
+ "ui_base_unittests",
+ "ui_chromeos_unittests",
+ "ui_touch_selection_unittests",
+ "unit_tests",
+ "url_unittests",
+ "views_unittests",
+ "wm_unittests"
],
"gtest_tests": [
{
@@ -46,16 +85,12 @@
"gn_unittests",
"google_apis_unittests",
"gpu_unittests",
+ "html_viewer_unittests",
"interactive_ui_tests",
"ipc_tests",
"jingle_unittests",
+ "mandoline:all",
"media_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"net_unittests",
"ppapi_unittests",
"printing_unittests",
@@ -69,6 +104,7 @@
"ui_touch_selection_unittests",
"unit_tests",
"url_unittests",
+ "view_manager_service_unittests",
"views_unittests",
"wm_unittests"
],
@@ -108,13 +144,8 @@
"ipc_mojo_unittests",
"ipc_tests",
"jingle_unittests",
+ "mandoline:all",
"media_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"net_unittests",
"ppapi_unittests",
"printing_unittests",
@@ -163,17 +194,13 @@
"gn_unittests",
"google_apis_unittests",
"gpu_unittests",
+ "html_viewer_unittests",
"interactive_ui_tests",
"ipc_mojo_unittests",
"ipc_tests",
"jingle_unittests",
+ "mandoline:all",
"media_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"nacl_loader_unittests",
"net_unittests",
"ppapi_unittests",
@@ -188,6 +215,7 @@
"ui_touch_selection_unittests",
"unit_tests",
"url_unittests",
+ "view_manager_service_unittests",
"views_unittests",
"wm_unittests"
],
diff --git a/testing/buildbot/tryserver.chromium.win.json b/testing/buildbot/tryserver.chromium.win.json
index 6710973..362c5e3 100644
--- a/testing/buildbot/tryserver.chromium.win.json
+++ b/testing/buildbot/tryserver.chromium.win.json
@@ -32,14 +32,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
@@ -94,14 +89,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
@@ -156,14 +146,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
@@ -218,14 +203,9 @@
"ipc_tests",
"jingle_unittests",
"keyboard_unittests",
+ "mandoline:all",
"media_unittests",
"message_center_unittests",
- "mojo_common_unittests",
- "mojo_public_bindings_unittests",
- "mojo_public_environment_unittests",
- "mojo_public_system_unittests",
- "mojo_public_utility_unittests",
- "mojo_system_unittests",
"ppapi_unittests",
"printing_unittests",
"sbox_integration_tests",
diff --git a/testing/chromoting/browser_test_commands_linux.txt b/testing/chromoting/browser_test_commands_linux.txt
index c9ecb29..dbe2aee 100644
--- a/testing/chromoting/browser_test_commands_linux.txt
+++ b/testing/chromoting/browser_test_commands_linux.txt
@@ -1,18 +1,18 @@
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_v2_Alive_OnLostFocus --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_Connect --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_InvalidAccessCode --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_CancelShare --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_VerifyAccessCodeNonReusable --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Cancel_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Update_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Invalid_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123457 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=FullscreenBrowserTest.MANUAL_Me2Me_Bump_Scroll --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_v2_Alive_OnLostFocus --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_Connect --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_InvalidAccessCode --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_CancelShare --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_VerifyAccessCodeNonReusable --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Cancel_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Update_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Invalid_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123457 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=FullscreenBrowserTest.MANUAL_Me2Me_Bump_Scroll --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
cd ../../remoting/internal/config && /usr/bin/python ./is_valid_json.py
\ No newline at end of file
diff --git a/testing/chromoting/browser_tests_launcher.py b/testing/chromoting/browser_tests_launcher.py
index 2fceb7c..1c9652f 100644
--- a/testing/chromoting/browser_tests_launcher.py
+++ b/testing/chromoting/browser_tests_launcher.py
@@ -13,6 +13,8 @@
import socket
import subprocess
+import psutil
+
BROWSER_TEST_ID = 'browser_tests'
PROD_DIR_ID = '#PROD_DIR#'
HOST_HASH_VALUE = hashlib.md5(socket.gethostname()).hexdigest()
@@ -162,6 +164,15 @@
shutil.copyfile(manifest_file_src, manifest_file_dest)
+def PrintRunningProcesses():
+ processes = psutil.get_process_list()
+ processes = sorted(processes, key=lambda process: process.name)
+
+ print 'List of running processes:\n'
+ for process in processes:
+ print process.name
+
+
def main(args):
InitialiseTestMachineForLinux(args.cfg_file)
@@ -182,6 +193,9 @@
# Host restart failed. Don't run any more tests.
raise Exception('Host restart failed.')
+ # Print list of currently running processes.
+ PrintRunningProcesses()
+
# All tests completed. Include host-logs in the test results.
host_log_contents = ''
# There should be only 1 log file, as we delete logs on test completion.
diff --git a/testing/commit_queue/config.json b/testing/commit_queue/config.json
index aefd3c7..3338304 100644
--- a/testing/commit_queue/config.json
+++ b/testing/commit_queue/config.json
@@ -30,15 +30,6 @@
"trybots": {
"launched": {
"tryserver.chromium.linux": {
- "android_amp_rel_tests_recipe": [
- "defaulttests"
- ],
- "linux_arm_compile": [
- "defaulttests"
- ],
- "linux_chromium_asan_rel_ng": [
- "defaulttests"
- ]
},
"tryserver.chromium.mac": {
"mac_chromium_gn_rel": [
@@ -60,7 +51,14 @@
"percentage": 1.0,
"trybots": {
"launched": {
- "tryserver.chromium.linux": {},
+ "tryserver.chromium.linux": {
+ "android_amp_rel_tests_recipe": [
+ "defaulttests"
+ ],
+ "linux_arm_compile": [
+ "defaulttests"
+ ]
+ },
"tryserver.chromium.mac": {}
}
}
@@ -118,7 +116,7 @@
"linux_android_rel_ng": [
"defaulttests"
],
- "linux_chromium_asan_rel": [
+ "linux_chromium_asan_rel_ng": [
"defaulttests"
],
"linux_chromium_chromeos_compile_dbg_ng": [
diff --git a/testing/scripts/telemetry_perf_unittests.py b/testing/scripts/telemetry_perf_unittests.py
index 42eb656..06e0181 100755
--- a/testing/scripts/telemetry_perf_unittests.py
+++ b/testing/scripts/telemetry_perf_unittests.py
@@ -16,16 +16,20 @@
if args.filter_file:
filter_tests = json.load(args.filter_file)
+ test_args = ['--retry-limit', '3']
+ if 'android' == args.properties.get('target_platform'):
+ test_args += ['--browser', 'android-chrome-shell', '--device', 'android']
+ else:
+ test_args += ['--browser', args.build_config_fs.lower()]
+
with common.temporary_file() as tempfile_path:
+ test_args += ['--write-full-results-to', tempfile_path]
rc = common.run_runtest(args, [
'--annotate', 'gtest',
'--test-type', 'telemetry_perf_unittests',
'--run-python-script',
- os.path.join(common.SRC_DIR, 'tools', 'perf', 'run_tests'),
- '--browser', args.build_config_fs.lower(),
- '--retry-limit', '3',
- '--write-full-results-to', tempfile_path,
- ] + filter_tests)
+ os.path.join(common.SRC_DIR, 'tools', 'perf', 'run_tests')
+ ] + test_args + filter_tests)
with open(tempfile_path) as f:
results = json.load(f)
@@ -43,7 +47,10 @@
def main_compile_targets(args):
- json.dump(['chrome'], args.output)
+ if 'android' == args.properties.get('target_platform'):
+ json.dump(['chrome_shell_apk'], args.output)
+ else:
+ json.dump(['chrome'], args.output)
if __name__ == '__main__':
diff --git a/third_party/libevent/README.chromium b/third_party/libevent/README.chromium
index a3e5c6e..939a353 100644
--- a/third_party/libevent/README.chromium
+++ b/third_party/libevent/README.chromium
@@ -24,3 +24,5 @@
nacl_nonsfi/random.c is also added to provide the random() function,
which is missing in the newlib-based PNaCl toolchain.
8) Apply https://github.com/libevent/libevent/commit/ea6b1df
+9) Stub out signal.c for nacl_helper_nonsfi. socketpair() will be prohibited
+ by sandbox in nacl_helper_nonsfi.
diff --git a/third_party/libevent/libevent_nacl_nonsfi.gyp b/third_party/libevent/libevent_nacl_nonsfi.gyp
index 37a78ad..2999ceb 100644
--- a/third_party/libevent/libevent_nacl_nonsfi.gyp
+++ b/third_party/libevent/libevent_nacl_nonsfi.gyp
@@ -19,11 +19,11 @@
'evutil.c',
'log.c',
'poll.c',
- 'signal.c',
'strlcpy.c',
'nacl_nonsfi/config.h',
'nacl_nonsfi/event-config.h',
'nacl_nonsfi/random.c',
+ 'nacl_nonsfi/signal_stub.c',
],
'defines': [
'HAVE_CONFIG_H',
diff --git a/third_party/libevent/nacl_nonsfi/signal_stub.c b/third_party/libevent/nacl_nonsfi/signal_stub.c
new file mode 100644
index 0000000..8049030
--- /dev/null
+++ b/third_party/libevent/nacl_nonsfi/signal_stub.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 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.
+ */
+
+/*
+ * In nacl_helper_nonsfi, socketpair() is unavailable. In libevent, it is used
+ * to notify of a signal handler invocation, which is unused in
+ * nacl_helper_nonsfi. Unfortunately, there is no macro to disable the feature,
+ * so we stub out the signal module entirely.
+ */
+
+
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+/* config.h must be included before any other libevent header is included. */
+#include "config.h"
+
+#include "third_party/libevent/event-internal.h"
+#include "third_party/libevent/event.h"
+#include "third_party/libevent/evsignal.h"
+
+
+struct event_base *evsignal_base = 0;
+
+int evsignal_init(struct event_base *base) {
+ /* Do nothing, and return success. */
+ return 0;
+}
+
+void evsignal_process(struct event_base *base) {
+}
+
+int evsignal_add(struct event *event) {
+ /* Do nothing, and return an error. */
+ return -1;
+}
+
+int evsignal_del(struct event *event) {
+ /* Do nothing, and return an error. */
+ return -1;
+}
+
+void evsignal_dealloc(struct event_base *base) {
+}
diff --git a/third_party/libxml/BUILD.gn b/third_party/libxml/BUILD.gn
index 299a110..7fb6678 100644
--- a/third_party/libxml/BUILD.gn
+++ b/third_party/libxml/BUILD.gn
@@ -65,8 +65,6 @@
"src/include/libxml/globals.h",
"src/include/libxml/hash.h",
"src/include/libxml/list.h",
- "src/include/libxml/nanoftp.h",
- "src/include/libxml/nanohttp.h",
"src/include/libxml/parser.h",
"src/include/libxml/parserInternals.h",
"src/include/libxml/pattern.h",
@@ -101,8 +99,6 @@
"src/legacy.c",
"src/libxml.h",
"src/list.c",
- "src/nanoftp.c",
- "src/nanohttp.c",
"src/parser.c",
"src/parserInternals.c",
"src/pattern.c",
diff --git a/third_party/libxml/OWNERS b/third_party/libxml/OWNERS
new file mode 100644
index 0000000..eb6ce62
--- /dev/null
+++ b/third_party/libxml/OWNERS
@@ -0,0 +1,4 @@
+# There's no real owners here. If you're familiar with the code please send
+# a CL to add yourself here.
+cpu@chromium.org
+scottmg@chromium.org
diff --git a/third_party/libxml/README.chromium b/third_party/libxml/README.chromium
index f12d267..1f3162f 100644
--- a/third_party/libxml/README.chromium
+++ b/third_party/libxml/README.chromium
@@ -22,21 +22,23 @@
- Add a fix for handling of unknown namespaces, commit upstream is pending.
- Add fixes for ending the parse properly if a SAX callback calls xmlStopParser(), commit upstream is pending.
- Add fix for entities, commit upstream is http://git.gnome.org/browse/libxml2/commit/?id=5bd3c061823a8499b27422aee04ea20aae24f03e
-- Import UTF-8 fix from upstream: http://git.gnome.org/browse/libxml2/commit/?id=0795348aeb86648723bc391e4d02e20631c10bca
+- Import UTF-8 fix from upstream: http://git.gnome.org/browse/libxml2/commit/?id=0795348aeb86648723bc391e4d02e20631c10bca
- Import XPath fix http://git.gnome.org/browse/libxml2/commit/xpath.c?id=2ddecc23862bab1a9a9e51e097aefc92ec305e28
- Merge clang warning fix http://git.gnome.org/browse/libxml2/commit/?id=aae48e64dfbf2b46b157a4c1857e30645116388f
- Add a fix for proper escaping of xpointer expressions, commit upstream is pending.
- Add helper classes in chromium/libxml_utils.cc and chromium/include/libxml/libxml_utils.h.
- Add a tweak to limit problems caused by excessive strings and buffers.
- Change the xmlNs struct a little bit, so it looks like it has no children
-- Prevent snprintf from being defined as _snprintf on VS 2015.
-if treated as a generic xmlNode object.
+ if treated as a generic xmlNode object.
- Fix pretty harmless use-after-free in generate-id function.
- Merge a clang warning fix http://git.gnome.org/browse/libxml2/commit/?id=713434d2309da469d64b35e163ea6556dadccada
- Import attribute normalization fix http://git.gnome.org/browse/libxml2/commit/?id=6a36fbe3b3e001a8a840b5c1fdd81cefc9947f0d
- Merge a redundant comparison fix http://git.gnome.org/browse/libxml2/commit/?id=2af19f985b911b6dc6ada478ba8d201d2ddc9309
- Merge a redundant comparisons fix https://git.gnome.org/browse/libxml2/commit/?id=eea38159be421dbafbee38f40e239f91734bc713
- Merge XML_PARSER_EOF checks https://git.gnome.org/browse/libxml2/commit/?id=48b4cdde3483e054af8ea02e0cd7ee467b0e9a50 and https://git.gnome.org/browse/libxml2/commit/?id=e50ba8164eee06461c73cd8abb9b46aa0be81869
+- Prevent snprintf from being defined as _snprintf on VS 2015.
+- Make ucrt of Win10 SDK not define POSIX error codes.
+- Delete/disable nanoftp and nanohttp.
To import a new snapshot of libxml:
diff --git a/third_party/libxml/libxml.gyp b/third_party/libxml/libxml.gyp
index 1decbe9..51e45db 100644
--- a/third_party/libxml/libxml.gyp
+++ b/third_party/libxml/libxml.gyp
@@ -96,8 +96,6 @@
'src/include/libxml/HTMLparser.h',
'src/include/libxml/HTMLtree.h',
'src/include/libxml/list.h',
- 'src/include/libxml/nanoftp.h',
- 'src/include/libxml/nanohttp.h',
'src/include/libxml/parser.h',
'src/include/libxml/parserInternals.h',
'src/include/libxml/pattern.h',
@@ -149,8 +147,6 @@
'src/legacy.c',
'src/libxml.h',
'src/list.c',
- 'src/nanoftp.c',
- 'src/nanohttp.c',
'src/parser.c',
'src/parserInternals.c',
'src/pattern.c',
diff --git a/third_party/libxml/patches/win32-no-posix-error-codes b/third_party/libxml/patches/win32-no-posix-error-codes
new file mode 100644
index 0000000..38be7f7
--- /dev/null
+++ b/third_party/libxml/patches/win32-no-posix-error-codes
@@ -0,0 +1,14 @@
+diff --git a/third_party/libxml/src/libxml.h b/third_party/libxml/src/libxml.h
+index 1656ac2..f8a368c 100644
+--- a/third_party/libxml/src/libxml.h
++++ b/third_party/libxml/src/libxml.h
+@@ -17,6 +17,9 @@
+ #define _FILE_OFFSET_BITS 64
+ #endif
+ #endif
++#ifndef _CRT_NO_POSIX_ERROR_CODES
++#define _CRT_NO_POSIX_ERROR_CODES
++#endif
+
+ #if defined(macintosh)
+ #include "config-mac.h"
diff --git a/third_party/libxml/src/include/libxml/nanoftp.h b/third_party/libxml/src/include/libxml/nanoftp.h
deleted file mode 100644
index e3c28a0..0000000
--- a/third_party/libxml/src/include/libxml/nanoftp.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Summary: minimal FTP implementation
- * Description: minimal FTP implementation allowing to fetch resources
- * like external subset.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Daniel Veillard
- */
-
-#ifndef __NANO_FTP_H__
-#define __NANO_FTP_H__
-
-#include <libxml/xmlversion.h>
-
-#ifdef LIBXML_FTP_ENABLED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * ftpListCallback:
- * @userData: user provided data for the callback
- * @filename: the file name (including "->" when links are shown)
- * @attrib: the attribute string
- * @owner: the owner string
- * @group: the group string
- * @size: the file size
- * @links: the link count
- * @year: the year
- * @month: the month
- * @day: the day
- * @hour: the hour
- * @minute: the minute
- *
- * A callback for the xmlNanoFTPList command.
- * Note that only one of year and day:minute are specified.
- */
-typedef void (*ftpListCallback) (void *userData,
- const char *filename, const char *attrib,
- const char *owner, const char *group,
- unsigned long size, int links, int year,
- const char *month, int day, int hour,
- int minute);
-/**
- * ftpDataCallback:
- * @userData: the user provided context
- * @data: the data received
- * @len: its size in bytes
- *
- * A callback for the xmlNanoFTPGet command.
- */
-typedef void (*ftpDataCallback) (void *userData,
- const char *data,
- int len);
-
-/*
- * Init
- */
-XMLPUBFUN void XMLCALL
- xmlNanoFTPInit (void);
-XMLPUBFUN void XMLCALL
- xmlNanoFTPCleanup (void);
-
-/*
- * Creating/freeing contexts.
- */
-XMLPUBFUN void * XMLCALL
- xmlNanoFTPNewCtxt (const char *URL);
-XMLPUBFUN void XMLCALL
- xmlNanoFTPFreeCtxt (void * ctx);
-XMLPUBFUN void * XMLCALL
- xmlNanoFTPConnectTo (const char *server,
- int port);
-/*
- * Opening/closing session connections.
- */
-XMLPUBFUN void * XMLCALL
- xmlNanoFTPOpen (const char *URL);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPConnect (void *ctx);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPClose (void *ctx);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPQuit (void *ctx);
-XMLPUBFUN void XMLCALL
- xmlNanoFTPScanProxy (const char *URL);
-XMLPUBFUN void XMLCALL
- xmlNanoFTPProxy (const char *host,
- int port,
- const char *user,
- const char *passwd,
- int type);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPUpdateURL (void *ctx,
- const char *URL);
-
-/*
- * Rather internal commands.
- */
-XMLPUBFUN int XMLCALL
- xmlNanoFTPGetResponse (void *ctx);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPCheckResponse (void *ctx);
-
-/*
- * CD/DIR/GET handlers.
- */
-XMLPUBFUN int XMLCALL
- xmlNanoFTPCwd (void *ctx,
- const char *directory);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPDele (void *ctx,
- const char *file);
-
-XMLPUBFUN int XMLCALL
- xmlNanoFTPGetConnection (void *ctx);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPCloseConnection(void *ctx);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPList (void *ctx,
- ftpListCallback callback,
- void *userData,
- const char *filename);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPGetSocket (void *ctx,
- const char *filename);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPGet (void *ctx,
- ftpDataCallback callback,
- void *userData,
- const char *filename);
-XMLPUBFUN int XMLCALL
- xmlNanoFTPRead (void *ctx,
- void *dest,
- int len);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* LIBXML_FTP_ENABLED */
-#endif /* __NANO_FTP_H__ */
diff --git a/third_party/libxml/src/include/libxml/nanohttp.h b/third_party/libxml/src/include/libxml/nanohttp.h
deleted file mode 100644
index 1d8ac24..0000000
--- a/third_party/libxml/src/include/libxml/nanohttp.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Summary: minimal HTTP implementation
- * Description: minimal HTTP implementation allowing to fetch resources
- * like external subset.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Daniel Veillard
- */
-
-#ifndef __NANO_HTTP_H__
-#define __NANO_HTTP_H__
-
-#include <libxml/xmlversion.h>
-
-#ifdef LIBXML_HTTP_ENABLED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-XMLPUBFUN void XMLCALL
- xmlNanoHTTPInit (void);
-XMLPUBFUN void XMLCALL
- xmlNanoHTTPCleanup (void);
-XMLPUBFUN void XMLCALL
- xmlNanoHTTPScanProxy (const char *URL);
-XMLPUBFUN int XMLCALL
- xmlNanoHTTPFetch (const char *URL,
- const char *filename,
- char **contentType);
-XMLPUBFUN void * XMLCALL
- xmlNanoHTTPMethod (const char *URL,
- const char *method,
- const char *input,
- char **contentType,
- const char *headers,
- int ilen);
-XMLPUBFUN void * XMLCALL
- xmlNanoHTTPMethodRedir (const char *URL,
- const char *method,
- const char *input,
- char **contentType,
- char **redir,
- const char *headers,
- int ilen);
-XMLPUBFUN void * XMLCALL
- xmlNanoHTTPOpen (const char *URL,
- char **contentType);
-XMLPUBFUN void * XMLCALL
- xmlNanoHTTPOpenRedir (const char *URL,
- char **contentType,
- char **redir);
-XMLPUBFUN int XMLCALL
- xmlNanoHTTPReturnCode (void *ctx);
-XMLPUBFUN const char * XMLCALL
- xmlNanoHTTPAuthHeader (void *ctx);
-XMLPUBFUN const char * XMLCALL
- xmlNanoHTTPRedir (void *ctx);
-XMLPUBFUN int XMLCALL
- xmlNanoHTTPContentLength( void * ctx );
-XMLPUBFUN const char * XMLCALL
- xmlNanoHTTPEncoding (void *ctx);
-XMLPUBFUN const char * XMLCALL
- xmlNanoHTTPMimeType (void *ctx);
-XMLPUBFUN int XMLCALL
- xmlNanoHTTPRead (void *ctx,
- void *dest,
- int len);
-#ifdef LIBXML_OUTPUT_ENABLED
-XMLPUBFUN int XMLCALL
- xmlNanoHTTPSave (void *ctxt,
- const char *filename);
-#endif /* LIBXML_OUTPUT_ENABLED */
-XMLPUBFUN void XMLCALL
- xmlNanoHTTPClose (void *ctx);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBXML_HTTP_ENABLED */
-#endif /* __NANO_HTTP_H__ */
diff --git a/third_party/libxml/src/libxml.h b/third_party/libxml/src/libxml.h
index 1656ac2..f8a368c 100644
--- a/third_party/libxml/src/libxml.h
+++ b/third_party/libxml/src/libxml.h
@@ -17,6 +17,9 @@
#define _FILE_OFFSET_BITS 64
#endif
#endif
+#ifndef _CRT_NO_POSIX_ERROR_CODES
+#define _CRT_NO_POSIX_ERROR_CODES
+#endif
#if defined(macintosh)
#include "config-mac.h"
diff --git a/third_party/libxml/src/nanoftp.c b/third_party/libxml/src/nanoftp.c
deleted file mode 100644
index a54b85b..0000000
--- a/third_party/libxml/src/nanoftp.c
+++ /dev/null
@@ -1,2111 +0,0 @@
-/*
- * nanoftp.c: basic FTP client support
- *
- * Reference: RFC 959
- */
-
-#ifdef TESTING
-#define STANDALONE
-#define HAVE_STDLIB_H
-#define HAVE_UNISTD_H
-#define HAVE_SYS_SOCKET_H
-#define HAVE_NETINET_IN_H
-#define HAVE_NETDB_H
-#define HAVE_SYS_TIME_H
-#else /* TESTING */
-#define NEED_SOCKETS
-#endif /* TESTING */
-
-#define IN_LIBXML
-#include "libxml.h"
-
-#ifdef LIBXML_FTP_ENABLED
-#include <string.h>
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/xmlerror.h>
-#include <libxml/uri.h>
-#include <libxml/nanoftp.h>
-#include <libxml/globals.h>
-
-/* #define DEBUG_FTP 1 */
-#ifdef STANDALONE
-#ifndef DEBUG_FTP
-#define DEBUG_FTP 1
-#endif
-#endif
-
-
-#if defined(__MINGW32__) || defined(_WIN32_WCE)
-#define _WINSOCKAPI_
-#include <wsockcompat.h>
-#include <winsock2.h>
-#undef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-
-/**
- * A couple portability macros
- */
-#ifndef _WINSOCKAPI_
-#if !defined(__BEOS__) || defined(__HAIKU__)
-#define closesocket(s) close(s)
-#endif
-#define SOCKET int
-#endif
-
-#ifdef __BEOS__
-#ifndef PF_INET
-#define PF_INET AF_INET
-#endif
-#endif
-
-#ifdef _AIX
-#ifdef HAVE_BROKEN_SS_FAMILY
-#define ss_family __ss_family
-#endif
-#endif
-
-#ifndef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-
-#define FTP_COMMAND_OK 200
-#define FTP_SYNTAX_ERROR 500
-#define FTP_GET_PASSWD 331
-#define FTP_BUF_SIZE 1024
-
-#define XML_NANO_MAX_URLBUF 4096
-
-typedef struct xmlNanoFTPCtxt {
- char *protocol; /* the protocol name */
- char *hostname; /* the host name */
- int port; /* the port */
- char *path; /* the path within the URL */
- char *user; /* user string */
- char *passwd; /* passwd string */
-#ifdef SUPPORT_IP6
- struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
-#else
- struct sockaddr_in ftpAddr; /* the socket address struct */
-#endif
- int passive; /* currently we support only passive !!! */
- SOCKET controlFd; /* the file descriptor for the control socket */
- SOCKET dataFd; /* the file descriptor for the data socket */
- int state; /* WRITE / READ / CLOSED */
- int returnValue; /* the protocol return value */
- /* buffer for data received from the control connection */
- char controlBuf[FTP_BUF_SIZE + 1];
- int controlBufIndex;
- int controlBufUsed;
- int controlBufAnswer;
-} xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
-
-static int initialized = 0;
-static char *proxy = NULL; /* the proxy name if any */
-static int proxyPort = 0; /* the proxy port if any */
-static char *proxyUser = NULL; /* user for proxy authentication */
-static char *proxyPasswd = NULL;/* passwd for proxy authentication */
-static int proxyType = 0; /* uses TYPE or a@b ? */
-
-#ifdef SUPPORT_IP6
-static
-int have_ipv6(void) {
- int s;
-
- s = socket (AF_INET6, SOCK_STREAM, 0);
- if (s != -1) {
- close (s);
- return (1);
- }
- return (0);
-}
-#endif
-
-/**
- * xmlFTPErrMemory:
- * @extra: extra informations
- *
- * Handle an out of memory condition
- */
-static void
-xmlFTPErrMemory(const char *extra)
-{
- __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
-}
-
-/**
- * xmlNanoFTPInit:
- *
- * Initialize the FTP protocol layer.
- * Currently it just checks for proxy informations,
- * and get the hostname
- */
-
-void
-xmlNanoFTPInit(void) {
- const char *env;
-#ifdef _WINSOCKAPI_
- WSADATA wsaData;
-#endif
-
- if (initialized)
- return;
-
-#ifdef _WINSOCKAPI_
- if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
- return;
-#endif
-
- proxyPort = 21;
- env = getenv("no_proxy");
- if (env && ((env[0] == '*' ) && (env[1] == 0)))
- return;
- env = getenv("ftp_proxy");
- if (env != NULL) {
- xmlNanoFTPScanProxy(env);
- } else {
- env = getenv("FTP_PROXY");
- if (env != NULL) {
- xmlNanoFTPScanProxy(env);
- }
- }
- env = getenv("ftp_proxy_user");
- if (env != NULL) {
- proxyUser = xmlMemStrdup(env);
- }
- env = getenv("ftp_proxy_password");
- if (env != NULL) {
- proxyPasswd = xmlMemStrdup(env);
- }
- initialized = 1;
-}
-
-/**
- * xmlNanoFTPCleanup:
- *
- * Cleanup the FTP protocol layer. This cleanup proxy informations.
- */
-
-void
-xmlNanoFTPCleanup(void) {
- if (proxy != NULL) {
- xmlFree(proxy);
- proxy = NULL;
- }
- if (proxyUser != NULL) {
- xmlFree(proxyUser);
- proxyUser = NULL;
- }
- if (proxyPasswd != NULL) {
- xmlFree(proxyPasswd);
- proxyPasswd = NULL;
- }
-#ifdef _WINSOCKAPI_
- if (initialized)
- WSACleanup();
-#endif
- initialized = 0;
-}
-
-/**
- * xmlNanoFTPProxy:
- * @host: the proxy host name
- * @port: the proxy port
- * @user: the proxy user name
- * @passwd: the proxy password
- * @type: the type of proxy 1 for using SITE, 2 for USER a@b
- *
- * Setup the FTP proxy informations.
- * This can also be done by using ftp_proxy ftp_proxy_user and
- * ftp_proxy_password environment variables.
- */
-
-void
-xmlNanoFTPProxy(const char *host, int port, const char *user,
- const char *passwd, int type) {
- if (proxy != NULL) {
- xmlFree(proxy);
- proxy = NULL;
- }
- if (proxyUser != NULL) {
- xmlFree(proxyUser);
- proxyUser = NULL;
- }
- if (proxyPasswd != NULL) {
- xmlFree(proxyPasswd);
- proxyPasswd = NULL;
- }
- if (host)
- proxy = xmlMemStrdup(host);
- if (user)
- proxyUser = xmlMemStrdup(user);
- if (passwd)
- proxyPasswd = xmlMemStrdup(passwd);
- proxyPort = port;
- proxyType = type;
-}
-
-/**
- * xmlNanoFTPScanURL:
- * @ctx: an FTP context
- * @URL: The URL used to initialize the context
- *
- * (Re)Initialize an FTP context by parsing the URL and finding
- * the protocol host port and path it indicates.
- */
-
-static void
-xmlNanoFTPScanURL(void *ctx, const char *URL) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- xmlURIPtr uri;
-
- /*
- * Clear any existing data from the context
- */
- if (ctxt->protocol != NULL) {
- xmlFree(ctxt->protocol);
- ctxt->protocol = NULL;
- }
- if (ctxt->hostname != NULL) {
- xmlFree(ctxt->hostname);
- ctxt->hostname = NULL;
- }
- if (ctxt->path != NULL) {
- xmlFree(ctxt->path);
- ctxt->path = NULL;
- }
- if (URL == NULL) return;
-
- uri = xmlParseURIRaw(URL, 1);
- if (uri == NULL)
- return;
-
- if ((uri->scheme == NULL) || (uri->server == NULL)) {
- xmlFreeURI(uri);
- return;
- }
-
- ctxt->protocol = xmlMemStrdup(uri->scheme);
- ctxt->hostname = xmlMemStrdup(uri->server);
- if (uri->path != NULL)
- ctxt->path = xmlMemStrdup(uri->path);
- else
- ctxt->path = xmlMemStrdup("/");
- if (uri->port != 0)
- ctxt->port = uri->port;
-
- if (uri->user != NULL) {
- char *cptr;
- if ((cptr=strchr(uri->user, ':')) == NULL)
- ctxt->user = xmlMemStrdup(uri->user);
- else {
- ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user,
- (cptr - uri->user));
- ctxt->passwd = xmlMemStrdup(cptr+1);
- }
- }
-
- xmlFreeURI(uri);
-
-}
-
-/**
- * xmlNanoFTPUpdateURL:
- * @ctx: an FTP context
- * @URL: The URL used to update the context
- *
- * Update an FTP context by parsing the URL and finding
- * new path it indicates. If there is an error in the
- * protocol, hostname, port or other information, the
- * error is raised. It indicates a new connection has to
- * be established.
- *
- * Returns 0 if Ok, -1 in case of error (other host).
- */
-
-int
-xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- xmlURIPtr uri;
-
- if (URL == NULL)
- return(-1);
- if (ctxt == NULL)
- return(-1);
- if (ctxt->protocol == NULL)
- return(-1);
- if (ctxt->hostname == NULL)
- return(-1);
-
- uri = xmlParseURIRaw(URL, 1);
- if (uri == NULL)
- return(-1);
-
- if ((uri->scheme == NULL) || (uri->server == NULL)) {
- xmlFreeURI(uri);
- return(-1);
- }
- if ((strcmp(ctxt->protocol, uri->scheme)) ||
- (strcmp(ctxt->hostname, uri->server)) ||
- ((uri->port != 0) && (ctxt->port != uri->port))) {
- xmlFreeURI(uri);
- return(-1);
- }
-
- if (uri->port != 0)
- ctxt->port = uri->port;
-
- if (ctxt->path != NULL) {
- xmlFree(ctxt->path);
- ctxt->path = NULL;
- }
-
- if (uri->path == NULL)
- ctxt->path = xmlMemStrdup("/");
- else
- ctxt->path = xmlMemStrdup(uri->path);
-
- xmlFreeURI(uri);
-
- return(0);
-}
-
-/**
- * xmlNanoFTPScanProxy:
- * @URL: The proxy URL used to initialize the proxy context
- *
- * (Re)Initialize the FTP Proxy context by parsing the URL and finding
- * the protocol host port it indicates.
- * Should be like ftp://myproxy/ or ftp://myproxy:3128/
- * A NULL URL cleans up proxy informations.
- */
-
-void
-xmlNanoFTPScanProxy(const char *URL) {
- xmlURIPtr uri;
-
- if (proxy != NULL) {
- xmlFree(proxy);
- proxy = NULL;
- }
- proxyPort = 0;
-
-#ifdef DEBUG_FTP
- if (URL == NULL)
- xmlGenericError(xmlGenericErrorContext,
- "Removing FTP proxy info\n");
- else
- xmlGenericError(xmlGenericErrorContext,
- "Using FTP proxy %s\n", URL);
-#endif
- if (URL == NULL) return;
-
- uri = xmlParseURIRaw(URL, 1);
- if ((uri == NULL) || (uri->scheme == NULL) ||
- (strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) {
- __xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n");
- if (uri != NULL)
- xmlFreeURI(uri);
- return;
- }
-
- proxy = xmlMemStrdup(uri->server);
- if (uri->port != 0)
- proxyPort = uri->port;
-
- xmlFreeURI(uri);
-}
-
-/**
- * xmlNanoFTPNewCtxt:
- * @URL: The URL used to initialize the context
- *
- * Allocate and initialize a new FTP context.
- *
- * Returns an FTP context or NULL in case of error.
- */
-
-void*
-xmlNanoFTPNewCtxt(const char *URL) {
- xmlNanoFTPCtxtPtr ret;
- char *unescaped;
-
- ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
- if (ret == NULL) {
- xmlFTPErrMemory("allocating FTP context");
- return(NULL);
- }
-
- memset(ret, 0, sizeof(xmlNanoFTPCtxt));
- ret->port = 21;
- ret->passive = 1;
- ret->returnValue = 0;
- ret->controlBufIndex = 0;
- ret->controlBufUsed = 0;
- ret->controlFd = -1;
-
- unescaped = xmlURIUnescapeString(URL, 0, NULL);
- if (unescaped != NULL) {
- xmlNanoFTPScanURL(ret, unescaped);
- xmlFree(unescaped);
- } else if (URL != NULL)
- xmlNanoFTPScanURL(ret, URL);
-
- return(ret);
-}
-
-/**
- * xmlNanoFTPFreeCtxt:
- * @ctx: an FTP context
- *
- * Frees the context after closing the connection.
- */
-
-void
-xmlNanoFTPFreeCtxt(void * ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- if (ctxt == NULL) return;
- if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
- if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
- if (ctxt->path != NULL) xmlFree(ctxt->path);
- ctxt->passive = 1;
- if (ctxt->controlFd >= 0) closesocket(ctxt->controlFd);
- ctxt->controlFd = -1;
- ctxt->controlBufIndex = -1;
- ctxt->controlBufUsed = -1;
- xmlFree(ctxt);
-}
-
-/**
- * xmlNanoFTPParseResponse:
- * @buf: the buffer containing the response
- * @len: the buffer length
- *
- * Parsing of the server answer, we just extract the code.
- *
- * returns 0 for errors
- * +XXX for last line of response
- * -XXX for response to be continued
- */
-static int
-xmlNanoFTPParseResponse(char *buf, int len) {
- int val = 0;
-
- if (len < 3) return(-1);
- if ((*buf >= '0') && (*buf <= '9'))
- val = val * 10 + (*buf - '0');
- else
- return(0);
- buf++;
- if ((*buf >= '0') && (*buf <= '9'))
- val = val * 10 + (*buf - '0');
- else
- return(0);
- buf++;
- if ((*buf >= '0') && (*buf <= '9'))
- val = val * 10 + (*buf - '0');
- else
- return(0);
- buf++;
- if (*buf == '-')
- return(-val);
- return(val);
-}
-
-/**
- * xmlNanoFTPGetMore:
- * @ctx: an FTP context
- *
- * Read more information from the FTP control connection
- * Returns the number of bytes read, < 0 indicates an error
- */
-static int
-xmlNanoFTPGetMore(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- int len;
- int size;
-
- if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
- if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoFTPGetMore : controlBufIndex = %d\n",
- ctxt->controlBufIndex);
-#endif
- return(-1);
- }
-
- if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoFTPGetMore : controlBufUsed = %d\n",
- ctxt->controlBufUsed);
-#endif
- return(-1);
- }
- if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
- ctxt->controlBufIndex, ctxt->controlBufUsed);
-#endif
- return(-1);
- }
-
- /*
- * First pack the control buffer
- */
- if (ctxt->controlBufIndex > 0) {
- memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
- ctxt->controlBufUsed - ctxt->controlBufIndex);
- ctxt->controlBufUsed -= ctxt->controlBufIndex;
- ctxt->controlBufIndex = 0;
- }
- size = FTP_BUF_SIZE - ctxt->controlBufUsed;
- if (size == 0) {
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
-#endif
- return(0);
- }
-
- /*
- * Read the amount left on the control connection
- */
- if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
- size, 0)) < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
- ctxt->controlBufUsed, ctxt->controlBufUsed + len);
-#endif
- ctxt->controlBufUsed += len;
- ctxt->controlBuf[ctxt->controlBufUsed] = 0;
-
- return(len);
-}
-
-/**
- * xmlNanoFTPReadResponse:
- * @ctx: an FTP context
- *
- * Read the response from the FTP server after a command.
- * Returns the code number
- */
-static int
-xmlNanoFTPReadResponse(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char *ptr, *end;
- int len;
- int res = -1, cur = -1;
-
- if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
-get_more:
- /*
- * Assumes everything up to controlBuf[controlBufIndex] has been read
- * and analyzed.
- */
- len = xmlNanoFTPGetMore(ctx);
- if (len < 0) {
- return(-1);
- }
- if ((ctxt->controlBufUsed == 0) && (len == 0)) {
- return(-1);
- }
- ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
- end = &ctxt->controlBuf[ctxt->controlBufUsed];
-
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext,
- "\n<<<\n%s\n--\n", ptr);
-#endif
- while (ptr < end) {
- cur = xmlNanoFTPParseResponse(ptr, end - ptr);
- if (cur > 0) {
- /*
- * Successfully scanned the control code, scratch
- * till the end of the line, but keep the index to be
- * able to analyze the result if needed.
- */
- res = cur;
- ptr += 3;
- ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
- while ((ptr < end) && (*ptr != '\n')) ptr++;
- if (*ptr == '\n') ptr++;
- if (*ptr == '\r') ptr++;
- break;
- }
- while ((ptr < end) && (*ptr != '\n')) ptr++;
- if (ptr >= end) {
- ctxt->controlBufIndex = ctxt->controlBufUsed;
- goto get_more;
- }
- if (*ptr != '\r') ptr++;
- }
-
- if (res < 0) goto get_more;
- ctxt->controlBufIndex = ptr - ctxt->controlBuf;
-#ifdef DEBUG_FTP
- ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
- xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
-#endif
-
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
-#endif
- return(res / 100);
-}
-
-/**
- * xmlNanoFTPGetResponse:
- * @ctx: an FTP context
- *
- * Get the response from the FTP server after a command.
- * Returns the code number
- */
-
-int
-xmlNanoFTPGetResponse(void *ctx) {
- int res;
-
- res = xmlNanoFTPReadResponse(ctx);
-
- return(res);
-}
-
-/**
- * xmlNanoFTPCheckResponse:
- * @ctx: an FTP context
- *
- * Check if there is a response from the FTP server after a command.
- * Returns the code number, or 0
- */
-
-int
-xmlNanoFTPCheckResponse(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- fd_set rfd;
- struct timeval tv;
-
- if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- FD_ZERO(&rfd);
- FD_SET(ctxt->controlFd, &rfd);
- switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
- case 0:
- return(0);
- case -1:
- __xmlIOErr(XML_FROM_FTP, 0, "select");
- return(-1);
-
- }
-
- return(xmlNanoFTPReadResponse(ctx));
-}
-
-/**
- * Send the user authentication
- */
-
-static int
-xmlNanoFTPSendUser(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[200];
- int len;
- int res;
-
- if (ctxt->user == NULL)
- snprintf(buf, sizeof(buf), "USER anonymous\r\n");
- else
- snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- return(res);
- }
- return(0);
-}
-
-/**
- * Send the password authentication
- */
-
-static int
-xmlNanoFTPSendPasswd(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[200];
- int len;
- int res;
-
- if (ctxt->passwd == NULL)
- snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
- else
- snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- return(res);
- }
- return(0);
-}
-
-/**
- * xmlNanoFTPQuit:
- * @ctx: an FTP context
- *
- * Send a QUIT command to the server
- *
- * Returns -1 in case of error, 0 otherwise
- */
-
-
-int
-xmlNanoFTPQuit(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[200];
- int len, res;
-
- if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
- snprintf(buf, sizeof(buf), "QUIT\r\n");
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- return(res);
- }
- return(0);
-}
-
-/**
- * xmlNanoFTPConnect:
- * @ctx: an FTP context
- *
- * Tries to open a control connection
- *
- * Returns -1 in case of error, 0 otherwise
- */
-
-int
-xmlNanoFTPConnect(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- struct hostent *hp;
- int port;
- int res;
- int addrlen = sizeof (struct sockaddr_in);
-
- if (ctxt == NULL)
- return(-1);
- if (ctxt->hostname == NULL)
- return(-1);
-
- /*
- * do the blocking DNS query.
- */
- if (proxy) {
- port = proxyPort;
- } else {
- port = ctxt->port;
- }
- if (port == 0)
- port = 21;
-
- memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
-
-#ifdef SUPPORT_IP6
- if (have_ipv6 ()) {
- struct addrinfo hints, *tmp, *result;
-
- result = NULL;
- memset (&hints, 0, sizeof(hints));
- hints.ai_socktype = SOCK_STREAM;
-
- if (proxy) {
- if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
- return (-1);
- }
- }
- else
- if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
- return (-1);
- }
-
- for (tmp = result; tmp; tmp = tmp->ai_next)
- if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
- break;
-
- if (!tmp) {
- if (result)
- freeaddrinfo (result);
- __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
- return (-1);
- }
- if (tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) {
- __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
- return (-1);
- }
- if (tmp->ai_family == AF_INET6) {
- memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
- ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
- ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
- }
- else {
- memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
- ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
- ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
- }
- addrlen = tmp->ai_addrlen;
- freeaddrinfo (result);
- }
- else
-#endif
- {
- if (proxy)
- hp = gethostbyname (proxy);
- else
- hp = gethostbyname (ctxt->hostname);
- if (hp == NULL) {
- __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
- return (-1);
- }
- if ((unsigned int) hp->h_length >
- sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) {
- __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
- return (-1);
- }
-
- /*
- * Prepare the socket
- */
- ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
- memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
- hp->h_addr_list[0], hp->h_length);
- ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = (u_short)htons ((unsigned short)port);
- ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
- addrlen = sizeof (struct sockaddr_in);
- }
-
- if (ctxt->controlFd < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
- return(-1);
- }
-
- /*
- * Do the connect.
- */
- if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
- addrlen) < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
-
- /*
- * Wait for the HELLO from the server.
- */
- res = xmlNanoFTPGetResponse(ctxt);
- if (res != 2) {
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
-
- /*
- * State diagram for the login operation on the FTP server
- *
- * Reference: RFC 959
- *
- * 1
- * +---+ USER +---+------------->+---+
- * | B |---------->| W | 2 ---->| E |
- * +---+ +---+------ | -->+---+
- * | | | | |
- * 3 | | 4,5 | | |
- * -------------- ----- | | |
- * | | | | |
- * | | | | |
- * | --------- |
- * | 1| | | |
- * V | | | |
- * +---+ PASS +---+ 2 | ------>+---+
- * | |---------->| W |------------->| S |
- * +---+ +---+ ---------->+---+
- * | | | | |
- * 3 | |4,5| | |
- * -------------- -------- |
- * | | | | |
- * | | | | |
- * | -----------
- * | 1,3| | | |
- * V | 2| | |
- * +---+ ACCT +---+-- | ----->+---+
- * | |---------->| W | 4,5 -------->| F |
- * +---+ +---+------------->+---+
- *
- * Of course in case of using a proxy this get really nasty and is not
- * standardized at all :-(
- */
- if (proxy) {
- int len;
- char buf[400];
-
- if (proxyUser != NULL) {
- /*
- * We need proxy auth
- */
- snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->controlFd);
- ctxt->controlFd = -1;
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- switch (res) {
- case 2:
- if (proxyPasswd == NULL)
- break;
- case 3:
- if (proxyPasswd != NULL)
- snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
- else
- snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->controlFd);
- ctxt->controlFd = -1;
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- if (res > 3) {
- closesocket(ctxt->controlFd);
- ctxt->controlFd = -1;
- return(-1);
- }
- break;
- case 1:
- break;
- case 4:
- case 5:
- case -1:
- default:
- closesocket(ctxt->controlFd);
- ctxt->controlFd = -1;
- return(-1);
- }
- }
-
- /*
- * We assume we don't need more authentication to the proxy
- * and that it succeeded :-\
- */
- switch (proxyType) {
- case 0:
- /* we will try in sequence */
- case 1:
- /* Using SITE command */
- snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- if (res == 2) {
- /* we assume it worked :-\ 1 is error for SITE command */
- proxyType = 1;
- break;
- }
- if (proxyType == 1) {
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
- case 2:
- /* USER user@host command */
- if (ctxt->user == NULL)
- snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
- ctxt->hostname);
- else
- snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
- ctxt->user, ctxt->hostname);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- if ((res == 1) || (res == 2)) {
- /* we assume it worked :-\ */
- proxyType = 2;
- return(0);
- }
- if (ctxt->passwd == NULL)
- snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
- else
- snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- if ((res == 1) || (res == 2)) {
- /* we assume it worked :-\ */
- proxyType = 2;
- return(0);
- }
- if (proxyType == 2) {
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
- case 3:
- /*
- * If you need support for other Proxy authentication scheme
- * send the code or at least the sequence in use.
- */
- default:
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
- }
- /*
- * Non-proxy handling.
- */
- res = xmlNanoFTPSendUser(ctxt);
- if (res < 0) {
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- switch (res) {
- case 2:
- return(0);
- case 3:
- break;
- case 1:
- case 4:
- case 5:
- case -1:
- default:
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
- res = xmlNanoFTPSendPasswd(ctxt);
- if (res < 0) {
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- switch (res) {
- case 2:
- break;
- case 3:
- __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
- "FTP server asking for ACCNT on anonymous\n");
- case 1:
- case 4:
- case 5:
- case -1:
- default:
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- ctxt->controlFd = -1;
- return(-1);
- }
-
- return(0);
-}
-
-/**
- * xmlNanoFTPConnectTo:
- * @server: an FTP server name
- * @port: the port (use 21 if 0)
- *
- * Tries to open a control connection to the given server/port
- *
- * Returns an fTP context or NULL if it failed
- */
-
-void*
-xmlNanoFTPConnectTo(const char *server, int port) {
- xmlNanoFTPCtxtPtr ctxt;
- int res;
-
- xmlNanoFTPInit();
- if (server == NULL)
- return(NULL);
- if (port <= 0)
- return(NULL);
- ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
- ctxt->hostname = xmlMemStrdup(server);
- if (port != 0)
- ctxt->port = port;
- res = xmlNanoFTPConnect(ctxt);
- if (res < 0) {
- xmlNanoFTPFreeCtxt(ctxt);
- return(NULL);
- }
- return(ctxt);
-}
-
-/**
- * xmlNanoFTPCwd:
- * @ctx: an FTP context
- * @directory: a directory on the server
- *
- * Tries to change the remote directory
- *
- * Returns -1 incase of error, 1 if CWD worked, 0 if it failed
- */
-
-int
-xmlNanoFTPCwd(void *ctx, const char *directory) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[400];
- int len;
- int res;
-
- if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
- if (directory == NULL) return 0;
-
- /*
- * Expected response code for CWD:
- *
- * CWD
- * 250
- * 500, 501, 502, 421, 530, 550
- */
- snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- if (res == 4) {
- return(-1);
- }
- if (res == 2) return(1);
- if (res == 5) {
- return(0);
- }
- return(0);
-}
-
-/**
- * xmlNanoFTPDele:
- * @ctx: an FTP context
- * @file: a file or directory on the server
- *
- * Tries to delete an item (file or directory) from server
- *
- * Returns -1 incase of error, 1 if DELE worked, 0 if it failed
- */
-
-int
-xmlNanoFTPDele(void *ctx, const char *file) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[400];
- int len;
- int res;
-
- if ((ctxt == NULL) || (ctxt->controlFd < 0) || (file == NULL)) return(-1);
- if (file == NULL) return (0);
-
- /*
- * Expected response code for DELE:
- *
- * DELE
- * 250
- * 450, 550
- * 500, 501, 502, 421, 530
- */
-
- snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- if (res == 4) {
- return(-1);
- }
- if (res == 2) return(1);
- if (res == 5) {
- return(0);
- }
- return(0);
-}
-/**
- * xmlNanoFTPGetConnection:
- * @ctx: an FTP context
- *
- * Try to open a data connection to the server. Currently only
- * passive mode is supported.
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPGetConnection(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[200], *cur;
- int len, i;
- int res;
- unsigned char ad[6], *adp, *portp;
- unsigned int temp[6];
-#ifdef SUPPORT_IP6
- struct sockaddr_storage dataAddr;
-#else
- struct sockaddr_in dataAddr;
-#endif
- XML_SOCKLEN_T dataAddrLen;
-
- if (ctxt == NULL) return(-1);
-
- memset (&dataAddr, 0, sizeof(dataAddr));
-#ifdef SUPPORT_IP6
- if ((ctxt->ftpAddr).ss_family == AF_INET6) {
- ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
- ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
- dataAddrLen = sizeof(struct sockaddr_in6);
- } else
-#endif
- {
- ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
- ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
- dataAddrLen = sizeof (struct sockaddr_in);
- }
-
- if (ctxt->dataFd < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
- return (-1);
- }
-
- if (ctxt->passive) {
-#ifdef SUPPORT_IP6
- if ((ctxt->ftpAddr).ss_family == AF_INET6)
- snprintf (buf, sizeof(buf), "EPSV\r\n");
- else
-#endif
- snprintf (buf, sizeof(buf), "PASV\r\n");
- len = strlen (buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(res);
- }
- res = xmlNanoFTPReadResponse(ctx);
- if (res != 2) {
- if (res == 5) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-1);
- } else {
- /*
- * retry with an active connection
- */
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- ctxt->passive = 0;
- }
- }
- cur = &ctxt->controlBuf[ctxt->controlBufAnswer];
- while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
-#ifdef SUPPORT_IP6
- if ((ctxt->ftpAddr).ss_family == AF_INET6) {
- if (sscanf (cur, "%u", &temp[0]) != 1) {
- __xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
- "Invalid answer to EPSV\n");
- if (ctxt->dataFd != -1) {
- closesocket (ctxt->dataFd); ctxt->dataFd = -1;
- }
- return (-1);
- }
- memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
- ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
- }
- else
-#endif
- {
- if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
- &temp[3], &temp[4], &temp[5]) != 6) {
- __xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
- "Invalid answer to PASV\n");
- if (ctxt->dataFd != -1) {
- closesocket (ctxt->dataFd); ctxt->dataFd = -1;
- }
- return (-1);
- }
- for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
- memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
- memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
- }
-
- if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return (-1);
- }
- } else {
- getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
-#ifdef SUPPORT_IP6
- if ((ctxt->ftpAddr).ss_family == AF_INET6)
- ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
- else
-#endif
- ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
-
- if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "bind failed");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return (-1);
- }
- getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
-
- if (listen(ctxt->dataFd, 1) < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "listen failed");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return (-1);
- }
-#ifdef SUPPORT_IP6
- if ((ctxt->ftpAddr).ss_family == AF_INET6) {
- char buf6[INET6_ADDRSTRLEN];
- inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
- buf6, INET6_ADDRSTRLEN);
- adp = (unsigned char *) buf6;
- portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
- snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
- } else
-#endif
- {
- adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
- portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
- snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
- adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
- portp[0] & 0xff, portp[1] & 0xff);
- }
-
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(res);
- }
- res = xmlNanoFTPGetResponse(ctxt);
- if (res != 2) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-1);
- }
- }
- return(ctxt->dataFd);
-
-}
-
-/**
- * xmlNanoFTPCloseConnection:
- * @ctx: an FTP context
- *
- * Close the data connection from the server
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPCloseConnection(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- int res;
- fd_set rfd, efd;
- struct timeval tv;
-
- if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- tv.tv_sec = 15;
- tv.tv_usec = 0;
- FD_ZERO(&rfd);
- FD_SET(ctxt->controlFd, &rfd);
- FD_ZERO(&efd);
- FD_SET(ctxt->controlFd, &efd);
- res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
- if (res < 0) {
-#ifdef DEBUG_FTP
- perror("select");
-#endif
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- return(-1);
- }
- if (res == 0) {
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoFTPCloseConnection: timeout\n");
-#endif
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- } else {
- res = xmlNanoFTPGetResponse(ctxt);
- if (res != 2) {
- closesocket(ctxt->controlFd); ctxt->controlFd = -1;
- return(-1);
- }
- }
- return(0);
-}
-
-/**
- * xmlNanoFTPParseList:
- * @list: some data listing received from the server
- * @callback: the user callback
- * @userData: the user callback data
- *
- * Parse at most one entry from the listing.
- *
- * Returns -1 incase of error, the length of data parsed otherwise
- */
-
-static int
-xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
- const char *cur = list;
- char filename[151];
- char attrib[11];
- char owner[11];
- char group[11];
- char month[4];
- int year = 0;
- int minute = 0;
- int hour = 0;
- int day = 0;
- unsigned long size = 0;
- int links = 0;
- int i;
-
- if (!strncmp(cur, "total", 5)) {
- cur += 5;
- while (*cur == ' ') cur++;
- while ((*cur >= '0') && (*cur <= '9'))
- links = (links * 10) + (*cur++ - '0');
- while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
- cur++;
- return(cur - list);
- } else if (*list == '+') {
- return(0);
- } else {
- while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
- cur++;
- if (*cur == 0) return(0);
- i = 0;
- while (*cur != ' ') {
- if (i < 10)
- attrib[i++] = *cur;
- cur++;
- if (*cur == 0) return(0);
- }
- attrib[10] = 0;
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- while ((*cur >= '0') && (*cur <= '9'))
- links = (links * 10) + (*cur++ - '0');
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- i = 0;
- while (*cur != ' ') {
- if (i < 10)
- owner[i++] = *cur;
- cur++;
- if (*cur == 0) return(0);
- }
- owner[i] = 0;
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- i = 0;
- while (*cur != ' ') {
- if (i < 10)
- group[i++] = *cur;
- cur++;
- if (*cur == 0) return(0);
- }
- group[i] = 0;
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- while ((*cur >= '0') && (*cur <= '9'))
- size = (size * 10) + (*cur++ - '0');
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- i = 0;
- while (*cur != ' ') {
- if (i < 3)
- month[i++] = *cur;
- cur++;
- if (*cur == 0) return(0);
- }
- month[i] = 0;
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- while ((*cur >= '0') && (*cur <= '9'))
- day = (day * 10) + (*cur++ - '0');
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- if ((cur[1] == 0) || (cur[2] == 0)) return(0);
- if ((cur[1] == ':') || (cur[2] == ':')) {
- while ((*cur >= '0') && (*cur <= '9'))
- hour = (hour * 10) + (*cur++ - '0');
- if (*cur == ':') cur++;
- while ((*cur >= '0') && (*cur <= '9'))
- minute = (minute * 10) + (*cur++ - '0');
- } else {
- while ((*cur >= '0') && (*cur <= '9'))
- year = (year * 10) + (*cur++ - '0');
- }
- while (*cur == ' ') cur++;
- if (*cur == 0) return(0);
- i = 0;
- while ((*cur != '\n') && (*cur != '\r')) {
- if (i < 150)
- filename[i++] = *cur;
- cur++;
- if (*cur == 0) return(0);
- }
- filename[i] = 0;
- if ((*cur != '\n') && (*cur != '\r'))
- return(0);
- while ((*cur == '\n') || (*cur == '\r'))
- cur++;
- }
- if (callback != NULL) {
- callback(userData, filename, attrib, owner, group, size, links,
- year, month, day, hour, minute);
- }
- return(cur - list);
-}
-
-/**
- * xmlNanoFTPList:
- * @ctx: an FTP context
- * @callback: the user callback
- * @userData: the user callback data
- * @filename: optional files to list
- *
- * Do a listing on the server. All files info are passed back
- * in the callbacks.
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
- const char *filename) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[4096 + 1];
- int len, res;
- int indx = 0, base;
- fd_set rfd, efd;
- struct timeval tv;
-
- if (ctxt == NULL) return (-1);
- if (filename == NULL) {
- if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
- return(-1);
- ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
- if (ctxt->dataFd == -1)
- return(-1);
- snprintf(buf, sizeof(buf), "LIST -L\r\n");
- } else {
- if (filename[0] != '/') {
- if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
- return(-1);
- }
- ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
- if (ctxt->dataFd == -1)
- return(-1);
- snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
- }
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(res);
- }
- res = xmlNanoFTPReadResponse(ctxt);
- if (res != 1) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-res);
- }
-
- do {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- FD_ZERO(&rfd);
- FD_SET(ctxt->dataFd, &rfd);
- FD_ZERO(&efd);
- FD_SET(ctxt->dataFd, &efd);
- res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
- if (res < 0) {
-#ifdef DEBUG_FTP
- perror("select");
-#endif
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-1);
- }
- if (res == 0) {
- res = xmlNanoFTPCheckResponse(ctxt);
- if (res < 0) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- ctxt->dataFd = -1;
- return(-1);
- }
- if (res == 2) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(0);
- }
-
- continue;
- }
-
- if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "recv");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- ctxt->dataFd = -1;
- return(-1);
- }
-#ifdef DEBUG_FTP
- write(1, &buf[indx], len);
-#endif
- indx += len;
- buf[indx] = 0;
- base = 0;
- do {
- res = xmlNanoFTPParseList(&buf[base], callback, userData);
- base += res;
- } while (res > 0);
-
- memmove(&buf[0], &buf[base], indx - base);
- indx -= base;
- } while (len != 0);
- xmlNanoFTPCloseConnection(ctxt);
- return(0);
-}
-
-/**
- * xmlNanoFTPGetSocket:
- * @ctx: an FTP context
- * @filename: the file to retrieve (or NULL if path is in context).
- *
- * Initiate fetch of the given file from the server.
- *
- * Returns the socket for the data connection, or <0 in case of error
- */
-
-
-int
-xmlNanoFTPGetSocket(void *ctx, const char *filename) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[300];
- int res, len;
- if (ctx == NULL)
- return(-1);
- if ((filename == NULL) && (ctxt->path == NULL))
- return(-1);
- ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
- if (ctxt->dataFd == -1)
- return(-1);
-
- snprintf(buf, sizeof(buf), "TYPE I\r\n");
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(res);
- }
- res = xmlNanoFTPReadResponse(ctxt);
- if (res != 2) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-res);
- }
- if (filename == NULL)
- snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
- else
- snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
- buf[sizeof(buf) - 1] = 0;
- len = strlen(buf);
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
- res = send(ctxt->controlFd, buf, len, 0);
- if (res < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "send failed");
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(res);
- }
- res = xmlNanoFTPReadResponse(ctxt);
- if (res != 1) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-res);
- }
- return(ctxt->dataFd);
-}
-
-/**
- * xmlNanoFTPGet:
- * @ctx: an FTP context
- * @callback: the user callback
- * @userData: the user callback data
- * @filename: the file to retrieve
- *
- * Fetch the given file from the server. All data are passed back
- * in the callbacks. The last callback has a size of 0 block.
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
- const char *filename) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
- char buf[4096];
- int len = 0, res;
- fd_set rfd;
- struct timeval tv;
-
- if (ctxt == NULL) return(-1);
- if ((filename == NULL) && (ctxt->path == NULL))
- return(-1);
- if (callback == NULL)
- return(-1);
- if (xmlNanoFTPGetSocket(ctxt, filename) < 0)
- return(-1);
-
- do {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- FD_ZERO(&rfd);
- FD_SET(ctxt->dataFd, &rfd);
- res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
- if (res < 0) {
-#ifdef DEBUG_FTP
- perror("select");
-#endif
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-1);
- }
- if (res == 0) {
- res = xmlNanoFTPCheckResponse(ctxt);
- if (res < 0) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- ctxt->dataFd = -1;
- return(-1);
- }
- if (res == 2) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(0);
- }
-
- continue;
- }
- if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
- __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
- callback(userData, buf, len);
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
- return(-1);
- }
- callback(userData, buf, len);
- } while (len != 0);
-
- return(xmlNanoFTPCloseConnection(ctxt));
-}
-
-/**
- * xmlNanoFTPRead:
- * @ctx: the FTP context
- * @dest: a buffer
- * @len: the buffer length
- *
- * This function tries to read @len bytes from the existing FTP connection
- * and saves them in @dest. This is a blocking call.
- *
- * Returns the number of byte read. 0 is an indication of an end of connection.
- * -1 indicates a parameter error.
- */
-int
-xmlNanoFTPRead(void *ctx, void *dest, int len) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-
- if (ctx == NULL) return(-1);
- if (ctxt->dataFd < 0) return(0);
- if (dest == NULL) return(-1);
- if (len <= 0) return(0);
-
- len = recv(ctxt->dataFd, dest, len, 0);
- if (len <= 0) {
- if (len < 0)
- __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
- xmlNanoFTPCloseConnection(ctxt);
- }
-#ifdef DEBUG_FTP
- xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
-#endif
- return(len);
-}
-
-/**
- * xmlNanoFTPOpen:
- * @URL: the URL to the resource
- *
- * Start to fetch the given ftp:// resource
- *
- * Returns an FTP context, or NULL
- */
-
-void*
-xmlNanoFTPOpen(const char *URL) {
- xmlNanoFTPCtxtPtr ctxt;
- int sock;
-
- xmlNanoFTPInit();
- if (URL == NULL) return(NULL);
- if (strncmp("ftp://", URL, 6)) return(NULL);
-
- ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
- if (ctxt == NULL) return(NULL);
- if (xmlNanoFTPConnect(ctxt) < 0) {
- xmlNanoFTPFreeCtxt(ctxt);
- return(NULL);
- }
- sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
- if (sock < 0) {
- xmlNanoFTPFreeCtxt(ctxt);
- return(NULL);
- }
- return(ctxt);
-}
-
-/**
- * xmlNanoFTPClose:
- * @ctx: an FTP context
- *
- * Close the connection and both control and transport
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPClose(void *ctx) {
- xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-
- if (ctxt == NULL)
- return(-1);
-
- if (ctxt->dataFd >= 0) {
- closesocket(ctxt->dataFd);
- ctxt->dataFd = -1;
- }
- if (ctxt->controlFd >= 0) {
- xmlNanoFTPQuit(ctxt);
- closesocket(ctxt->controlFd);
- ctxt->controlFd = -1;
- }
- xmlNanoFTPFreeCtxt(ctxt);
- return(0);
-}
-
-#ifdef STANDALONE
-/************************************************************************
- * *
- * Basic test in Standalone mode *
- * *
- ************************************************************************/
-static
-void ftpList(void *userData, const char *filename, const char* attrib,
- const char *owner, const char *group, unsigned long size, int links,
- int year, const char *month, int day, int hour, int minute) {
- xmlGenericError(xmlGenericErrorContext,
- "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
-}
-static
-void ftpData(void *userData, const char *data, int len) {
- if (userData == NULL) return;
- if (len <= 0) {
- fclose((FILE*)userData);
- return;
- }
- fwrite(data, len, 1, (FILE*)userData);
-}
-
-int main(int argc, char **argv) {
- void *ctxt;
- FILE *output;
- char *tstfile = NULL;
-
- xmlNanoFTPInit();
- if (argc > 1) {
- ctxt = xmlNanoFTPNewCtxt(argv[1]);
- if (xmlNanoFTPConnect(ctxt) < 0) {
- xmlGenericError(xmlGenericErrorContext,
- "Couldn't connect to %s\n", argv[1]);
- exit(1);
- }
- if (argc > 2)
- tstfile = argv[2];
- } else
- ctxt = xmlNanoFTPConnectTo("localhost", 0);
- if (ctxt == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "Couldn't connect to localhost\n");
- exit(1);
- }
- xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
- output = fopen("/tmp/tstdata", "w");
- if (output != NULL) {
- if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
- xmlGenericError(xmlGenericErrorContext,
- "Failed to get file\n");
-
- }
- xmlNanoFTPClose(ctxt);
- xmlMemoryDump();
- exit(0);
-}
-#endif /* STANDALONE */
-#else /* !LIBXML_FTP_ENABLED */
-#ifdef STANDALONE
-#include <stdio.h>
-int main(int argc, char **argv) {
- xmlGenericError(xmlGenericErrorContext,
- "%s : FTP support not compiled in\n", argv[0]);
- return(0);
-}
-#endif /* STANDALONE */
-#endif /* LIBXML_FTP_ENABLED */
-#define bottom_nanoftp
-#include "elfgcchack.h"
diff --git a/third_party/libxml/src/nanohttp.c b/third_party/libxml/src/nanohttp.c
deleted file mode 100644
index 542c4ea..0000000
--- a/third_party/libxml/src/nanohttp.c
+++ /dev/null
@@ -1,1875 +0,0 @@
-/*
- * nanohttp.c: minimalist HTTP GET implementation to fetch external subsets.
- * focuses on size, streamability, reentrancy and portability
- *
- * This is clearly not a general purpose HTTP implementation
- * If you look for one, check:
- * http://www.w3.org/Library/
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define NEED_SOCKETS
-#define IN_LIBXML
-#include "libxml.h"
-
-#ifdef LIBXML_HTTP_ENABLED
-#include <string.h>
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_RESOLV_H
-#ifdef HAVE_ARPA_NAMESER_H
-#include <arpa/nameser.h>
-#endif
-#include <resolv.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifndef HAVE_POLL_H
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#else
-#include <poll.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#ifdef SUPPORT_IP6
-#include <resolv.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-
-#ifdef VMS
-#include <stropts>
-#define XML_SOCKLEN_T unsigned int
-#define SOCKET int
-#endif
-
-#if defined(__MINGW32__) || defined(_WIN32_WCE)
-#define _WINSOCKAPI_
-#include <wsockcompat.h>
-#include <winsock2.h>
-#undef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-
-
-#include <libxml/globals.h>
-#include <libxml/xmlerror.h>
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h> /* for xmlStr(n)casecmp() */
-#include <libxml/nanohttp.h>
-#include <libxml/globals.h>
-#include <libxml/uri.h>
-
-/**
- * A couple portability macros
- */
-#ifndef _WINSOCKAPI_
-#if !defined(__BEOS__) || defined(__HAIKU__)
-#define closesocket(s) close(s)
-#endif
-#define SOCKET int
-#endif
-
-#ifdef __BEOS__
-#ifndef PF_INET
-#define PF_INET AF_INET
-#endif
-#endif
-
-#ifndef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-#ifndef SOCKET
-#define SOCKET int
-#endif
-
-#ifdef STANDALONE
-#define DEBUG_HTTP
-#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
-#define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
-#endif
-
-#define XML_NANO_HTTP_MAX_REDIR 10
-
-#define XML_NANO_HTTP_CHUNK 4096
-
-#define XML_NANO_HTTP_CLOSED 0
-#define XML_NANO_HTTP_WRITE 1
-#define XML_NANO_HTTP_READ 2
-#define XML_NANO_HTTP_NONE 4
-
-typedef struct xmlNanoHTTPCtxt {
- char *protocol; /* the protocol name */
- char *hostname; /* the host name */
- int port; /* the port */
- char *path; /* the path within the URL */
- char *query; /* the query string */
- SOCKET fd; /* the file descriptor for the socket */
- int state; /* WRITE / READ / CLOSED */
- char *out; /* buffer sent (zero terminated) */
- char *outptr; /* index within the buffer sent */
- char *in; /* the receiving buffer */
- char *content; /* the start of the content */
- char *inptr; /* the next byte to read from network */
- char *inrptr; /* the next byte to give back to the client */
- int inlen; /* len of the input buffer */
- int last; /* return code for last operation */
- int returnValue; /* the protocol return value */
- int version; /* the protocol version */
- int ContentLength; /* specified content length from HTTP header */
- char *contentType; /* the MIME type for the input */
- char *location; /* the new URL in case of redirect */
- char *authHeader; /* contents of {WWW,Proxy}-Authenticate header */
- char *encoding; /* encoding extracted from the contentType */
- char *mimeType; /* Mime-Type extracted from the contentType */
-#ifdef HAVE_ZLIB_H
- z_stream *strm; /* Zlib stream object */
- int usesGzip; /* "Content-Encoding: gzip" was detected */
-#endif
-} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
-
-static int initialized = 0;
-static char *proxy = NULL; /* the proxy name if any */
-static int proxyPort; /* the proxy port if any */
-static unsigned int timeout = 60;/* the select() timeout in seconds */
-
-static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len );
-
-/**
- * xmlHTTPErrMemory:
- * @extra: extra informations
- *
- * Handle an out of memory condition
- */
-static void
-xmlHTTPErrMemory(const char *extra)
-{
- __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
-}
-
-/**
- * A portability function
- */
-static int socket_errno(void) {
-#ifdef _WINSOCKAPI_
- return(WSAGetLastError());
-#else
- return(errno);
-#endif
-}
-
-#ifdef SUPPORT_IP6
-static
-int have_ipv6(void) {
- int s;
-
- s = socket (AF_INET6, SOCK_STREAM, 0);
- if (s != -1) {
- close (s);
- return (1);
- }
- return (0);
-}
-#endif
-
-/**
- * xmlNanoHTTPInit:
- *
- * Initialize the HTTP protocol layer.
- * Currently it just checks for proxy informations
- */
-
-void
-xmlNanoHTTPInit(void) {
- const char *env;
-#ifdef _WINSOCKAPI_
- WSADATA wsaData;
-#endif
-
- if (initialized)
- return;
-
-#ifdef _WINSOCKAPI_
- if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
- return;
-#endif
-
- if (proxy == NULL) {
- proxyPort = 80;
- env = getenv("no_proxy");
- if (env && ((env[0] == '*') && (env[1] == 0)))
- goto done;
- env = getenv("http_proxy");
- if (env != NULL) {
- xmlNanoHTTPScanProxy(env);
- goto done;
- }
- env = getenv("HTTP_PROXY");
- if (env != NULL) {
- xmlNanoHTTPScanProxy(env);
- goto done;
- }
- }
-done:
- initialized = 1;
-}
-
-/**
- * xmlNanoHTTPCleanup:
- *
- * Cleanup the HTTP protocol layer.
- */
-
-void
-xmlNanoHTTPCleanup(void) {
- if (proxy != NULL) {
- xmlFree(proxy);
- proxy = NULL;
- }
-#ifdef _WINSOCKAPI_
- if (initialized)
- WSACleanup();
-#endif
- initialized = 0;
- return;
-}
-
-/**
- * xmlNanoHTTPScanURL:
- * @ctxt: an HTTP context
- * @URL: The URL used to initialize the context
- *
- * (Re)Initialize an HTTP context by parsing the URL and finding
- * the protocol host port and path it indicates.
- */
-
-static void
-xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
- xmlURIPtr uri;
- /*
- * Clear any existing data from the context
- */
- if (ctxt->protocol != NULL) {
- xmlFree(ctxt->protocol);
- ctxt->protocol = NULL;
- }
- if (ctxt->hostname != NULL) {
- xmlFree(ctxt->hostname);
- ctxt->hostname = NULL;
- }
- if (ctxt->path != NULL) {
- xmlFree(ctxt->path);
- ctxt->path = NULL;
- }
- if (ctxt->query != NULL) {
- xmlFree(ctxt->query);
- ctxt->query = NULL;
- }
- if (URL == NULL) return;
-
- uri = xmlParseURIRaw(URL, 1);
- if (uri == NULL)
- return;
-
- if ((uri->scheme == NULL) || (uri->server == NULL)) {
- xmlFreeURI(uri);
- return;
- }
-
- ctxt->protocol = xmlMemStrdup(uri->scheme);
- ctxt->hostname = xmlMemStrdup(uri->server);
- if (uri->path != NULL)
- ctxt->path = xmlMemStrdup(uri->path);
- else
- ctxt->path = xmlMemStrdup("/");
- if (uri->query != NULL)
- ctxt->query = xmlMemStrdup(uri->query);
- if (uri->port != 0)
- ctxt->port = uri->port;
-
- xmlFreeURI(uri);
-}
-
-/**
- * xmlNanoHTTPScanProxy:
- * @URL: The proxy URL used to initialize the proxy context
- *
- * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
- * the protocol host port it indicates.
- * Should be like http://myproxy/ or http://myproxy:3128/
- * A NULL URL cleans up proxy informations.
- */
-
-void
-xmlNanoHTTPScanProxy(const char *URL) {
- xmlURIPtr uri;
-
- if (proxy != NULL) {
- xmlFree(proxy);
- proxy = NULL;
- }
- proxyPort = 0;
-
-#ifdef DEBUG_HTTP
- if (URL == NULL)
- xmlGenericError(xmlGenericErrorContext,
- "Removing HTTP proxy info\n");
- else
- xmlGenericError(xmlGenericErrorContext,
- "Using HTTP proxy %s\n", URL);
-#endif
- if (URL == NULL) return;
-
- uri = xmlParseURIRaw(URL, 1);
- if ((uri == NULL) || (uri->scheme == NULL) ||
- (strcmp(uri->scheme, "http")) || (uri->server == NULL)) {
- __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n");
- if (uri != NULL)
- xmlFreeURI(uri);
- return;
- }
-
- proxy = xmlMemStrdup(uri->server);
- if (uri->port != 0)
- proxyPort = uri->port;
-
- xmlFreeURI(uri);
-}
-
-/**
- * xmlNanoHTTPNewCtxt:
- * @URL: The URL used to initialize the context
- *
- * Allocate and initialize a new HTTP context.
- *
- * Returns an HTTP context or NULL in case of error.
- */
-
-static xmlNanoHTTPCtxtPtr
-xmlNanoHTTPNewCtxt(const char *URL) {
- xmlNanoHTTPCtxtPtr ret;
-
- ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
- if (ret == NULL) {
- xmlHTTPErrMemory("allocating context");
- return(NULL);
- }
-
- memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
- ret->port = 80;
- ret->returnValue = 0;
- ret->fd = -1;
- ret->ContentLength = -1;
-
- xmlNanoHTTPScanURL(ret, URL);
-
- return(ret);
-}
-
-/**
- * xmlNanoHTTPFreeCtxt:
- * @ctxt: an HTTP context
- *
- * Frees the context after closing the connection.
- */
-
-static void
-xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
- if (ctxt == NULL) return;
- if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
- if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
- if (ctxt->path != NULL) xmlFree(ctxt->path);
- if (ctxt->query != NULL) xmlFree(ctxt->query);
- if (ctxt->out != NULL) xmlFree(ctxt->out);
- if (ctxt->in != NULL) xmlFree(ctxt->in);
- if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
- if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
- if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
- if (ctxt->location != NULL) xmlFree(ctxt->location);
- if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
-#ifdef HAVE_ZLIB_H
- if (ctxt->strm != NULL) {
- inflateEnd(ctxt->strm);
- xmlFree(ctxt->strm);
- }
-#endif
-
- ctxt->state = XML_NANO_HTTP_NONE;
- if (ctxt->fd >= 0) closesocket(ctxt->fd);
- ctxt->fd = -1;
- xmlFree(ctxt);
-}
-
-/**
- * xmlNanoHTTPSend:
- * @ctxt: an HTTP context
- *
- * Send the input needed to initiate the processing on the server side
- * Returns number of bytes sent or -1 on error.
- */
-
-static int
-xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
-{
- int total_sent = 0;
-#ifdef HAVE_POLL_H
- struct pollfd p;
-#else
- struct timeval tv;
- fd_set wfd;
-#endif
-
- if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
- while (total_sent < outlen) {
- int nsent = send(ctxt->fd, xmt_ptr + total_sent,
- outlen - total_sent, 0);
-
- if (nsent > 0)
- total_sent += nsent;
- else if ((nsent == -1) &&
-#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
- (socket_errno() != EAGAIN) &&
-#endif
- (socket_errno() != EWOULDBLOCK)) {
- __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
- if (total_sent == 0)
- total_sent = -1;
- break;
- } else {
- /*
- * No data sent
- * Since non-blocking sockets are used, wait for
- * socket to be writable or default timeout prior
- * to retrying.
- */
-#ifndef HAVE_POLL_H
-#ifndef _WINSOCKAPI_
- if (ctxt->fd > FD_SETSIZE)
- return -1;
-#endif
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- FD_ZERO(&wfd);
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4018)
-#endif
- FD_SET(ctxt->fd, &wfd);
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
- (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
-#else
- p.fd = ctxt->fd;
- p.events = POLLOUT;
- (void) poll(&p, 1, timeout * 1000);
-#endif /* !HAVE_POLL_H */
- }
- }
- }
-
- return total_sent;
-}
-
-/**
- * xmlNanoHTTPRecv:
- * @ctxt: an HTTP context
- *
- * Read information coming from the HTTP connection.
- * This is a blocking call (but it blocks in select(), not read()).
- *
- * Returns the number of byte read or -1 in case of error.
- */
-
-static int
-xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
-{
-#ifdef HAVE_POLL_H
- struct pollfd p;
-#else
- fd_set rfd;
- struct timeval tv;
-#endif
-
-
- while (ctxt->state & XML_NANO_HTTP_READ) {
- if (ctxt->in == NULL) {
- ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
- if (ctxt->in == NULL) {
- xmlHTTPErrMemory("allocating input");
- ctxt->last = -1;
- return (-1);
- }
- ctxt->inlen = 65000;
- ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
- }
- if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
- int delta = ctxt->inrptr - ctxt->in;
- int len = ctxt->inptr - ctxt->inrptr;
-
- memmove(ctxt->in, ctxt->inrptr, len);
- ctxt->inrptr -= delta;
- ctxt->content -= delta;
- ctxt->inptr -= delta;
- }
- if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
- int d_inptr = ctxt->inptr - ctxt->in;
- int d_content = ctxt->content - ctxt->in;
- int d_inrptr = ctxt->inrptr - ctxt->in;
- char *tmp_ptr = ctxt->in;
-
- ctxt->inlen *= 2;
- ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
- if (ctxt->in == NULL) {
- xmlHTTPErrMemory("allocating input buffer");
- xmlFree(tmp_ptr);
- ctxt->last = -1;
- return (-1);
- }
- ctxt->inptr = ctxt->in + d_inptr;
- ctxt->content = ctxt->in + d_content;
- ctxt->inrptr = ctxt->in + d_inrptr;
- }
- ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
- if (ctxt->last > 0) {
- ctxt->inptr += ctxt->last;
- return (ctxt->last);
- }
- if (ctxt->last == 0) {
- return (0);
- }
- if (ctxt->last == -1) {
- switch (socket_errno()) {
- case EINPROGRESS:
- case EWOULDBLOCK:
-#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
- case EAGAIN:
-#endif
- break;
-
- case ECONNRESET:
- case ESHUTDOWN:
- return (0);
-
- default:
- __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
- return (-1);
- }
- }
-#ifdef HAVE_POLL_H
- p.fd = ctxt->fd;
- p.events = POLLIN;
- if ((poll(&p, 1, timeout * 1000) < 1)
-#if defined(EINTR)
- && (errno != EINTR)
-#endif
- )
- return (0);
-#else /* !HAVE_POLL_H */
-#ifndef _WINSOCKAPI_
- if (ctxt->fd > FD_SETSIZE)
- return 0;
-#endif
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- FD_ZERO(&rfd);
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4018)
-#endif
-
- FD_SET(ctxt->fd, &rfd);
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
- if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
-#if defined(EINTR)
- && (errno != EINTR)
-#endif
- )
- return (0);
-#endif /* !HAVE_POLL_H */
- }
- return (0);
-}
-
-/**
- * xmlNanoHTTPReadLine:
- * @ctxt: an HTTP context
- *
- * Read one line in the HTTP server output, usually for extracting
- * the HTTP protocol informations from the answer header.
- *
- * Returns a newly allocated string with a copy of the line, or NULL
- * which indicate the end of the input.
- */
-
-static char *
-xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
- char buf[4096];
- char *bp = buf;
- int rc;
-
- while (bp - buf < 4095) {
- if (ctxt->inrptr == ctxt->inptr) {
- if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
- if (bp == buf)
- return(NULL);
- else
- *bp = 0;
- return(xmlMemStrdup(buf));
- }
- else if ( rc == -1 ) {
- return ( NULL );
- }
- }
- *bp = *ctxt->inrptr++;
- if (*bp == '\n') {
- *bp = 0;
- return(xmlMemStrdup(buf));
- }
- if (*bp != '\r')
- bp++;
- }
- buf[4095] = 0;
- return(xmlMemStrdup(buf));
-}
-
-
-/**
- * xmlNanoHTTPScanAnswer:
- * @ctxt: an HTTP context
- * @line: an HTTP header line
- *
- * Try to extract useful informations from the server answer.
- * We currently parse and process:
- * - The HTTP revision/ return code
- * - The Content-Type, Mime-Type and charset used
- * - The Location for redirect processing.
- *
- * Returns -1 in case of failure, the file descriptor number otherwise
- */
-
-static void
-xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
- const char *cur = line;
-
- if (line == NULL) return;
-
- if (!strncmp(line, "HTTP/", 5)) {
- int version = 0;
- int ret = 0;
-
- cur += 5;
- while ((*cur >= '0') && (*cur <= '9')) {
- version *= 10;
- version += *cur - '0';
- cur++;
- }
- if (*cur == '.') {
- cur++;
- if ((*cur >= '0') && (*cur <= '9')) {
- version *= 10;
- version += *cur - '0';
- cur++;
- }
- while ((*cur >= '0') && (*cur <= '9'))
- cur++;
- } else
- version *= 10;
- if ((*cur != ' ') && (*cur != '\t')) return;
- while ((*cur == ' ') || (*cur == '\t')) cur++;
- if ((*cur < '0') || (*cur > '9')) return;
- while ((*cur >= '0') && (*cur <= '9')) {
- ret *= 10;
- ret += *cur - '0';
- cur++;
- }
- if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
- ctxt->returnValue = ret;
- ctxt->version = version;
- } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
- const xmlChar *charset, *last, *mime;
- cur += 13;
- while ((*cur == ' ') || (*cur == '\t')) cur++;
- if (ctxt->contentType != NULL)
- xmlFree(ctxt->contentType);
- ctxt->contentType = xmlMemStrdup(cur);
- mime = (const xmlChar *) cur;
- last = mime;
- while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
- (*last != ';') && (*last != ','))
- last++;
- if (ctxt->mimeType != NULL)
- xmlFree(ctxt->mimeType);
- ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
- charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
- if (charset != NULL) {
- charset += 8;
- last = charset;
- while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
- (*last != ';') && (*last != ','))
- last++;
- if (ctxt->encoding != NULL)
- xmlFree(ctxt->encoding);
- ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
- }
- } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
- const xmlChar *charset, *last, *mime;
- cur += 12;
- if (ctxt->contentType != NULL) return;
- while ((*cur == ' ') || (*cur == '\t')) cur++;
- ctxt->contentType = xmlMemStrdup(cur);
- mime = (const xmlChar *) cur;
- last = mime;
- while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
- (*last != ';') && (*last != ','))
- last++;
- if (ctxt->mimeType != NULL)
- xmlFree(ctxt->mimeType);
- ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
- charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
- if (charset != NULL) {
- charset += 8;
- last = charset;
- while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
- (*last != ';') && (*last != ','))
- last++;
- if (ctxt->encoding != NULL)
- xmlFree(ctxt->encoding);
- ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
- }
- } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
- cur += 9;
- while ((*cur == ' ') || (*cur == '\t')) cur++;
- if (ctxt->location != NULL)
- xmlFree(ctxt->location);
- if (*cur == '/') {
- xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
- xmlChar *tmp_loc =
- xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
- ctxt->location =
- (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
- } else {
- ctxt->location = xmlMemStrdup(cur);
- }
- } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
- cur += 17;
- while ((*cur == ' ') || (*cur == '\t')) cur++;
- if (ctxt->authHeader != NULL)
- xmlFree(ctxt->authHeader);
- ctxt->authHeader = xmlMemStrdup(cur);
- } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
- cur += 19;
- while ((*cur == ' ') || (*cur == '\t')) cur++;
- if (ctxt->authHeader != NULL)
- xmlFree(ctxt->authHeader);
- ctxt->authHeader = xmlMemStrdup(cur);
-#ifdef HAVE_ZLIB_H
- } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
- cur += 17;
- while ((*cur == ' ') || (*cur == '\t')) cur++;
- if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
- ctxt->usesGzip = 1;
-
- ctxt->strm = xmlMalloc(sizeof(z_stream));
-
- if (ctxt->strm != NULL) {
- ctxt->strm->zalloc = Z_NULL;
- ctxt->strm->zfree = Z_NULL;
- ctxt->strm->opaque = Z_NULL;
- ctxt->strm->avail_in = 0;
- ctxt->strm->next_in = Z_NULL;
-
- inflateInit2( ctxt->strm, 31 );
- }
- }
-#endif
- } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
- cur += 15;
- ctxt->ContentLength = strtol( cur, NULL, 10 );
- }
-}
-
-/**
- * xmlNanoHTTPConnectAttempt:
- * @addr: a socket address structure
- *
- * Attempt a connection to the given IP:port endpoint. It forces
- * non-blocking semantic on the socket, and allow 60 seconds for
- * the host to answer.
- *
- * Returns -1 in case of failure, the file descriptor number otherwise
- */
-
-static int
-xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
-{
-#ifndef HAVE_POLL_H
- fd_set wfd;
-#ifdef _WINSOCKAPI_
- fd_set xfd;
-#endif
- struct timeval tv;
-#else /* !HAVE_POLL_H */
- struct pollfd p;
-#endif /* !HAVE_POLL_H */
- int status;
-
- int addrlen;
-
- SOCKET s;
-
-#ifdef SUPPORT_IP6
- if (addr->sa_family == AF_INET6) {
- s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
- addrlen = sizeof(struct sockaddr_in6);
- } else
-#endif
- {
- s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- addrlen = sizeof(struct sockaddr_in);
- }
- if (s == -1) {
-#ifdef DEBUG_HTTP
- perror("socket");
-#endif
- __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
- return (-1);
- }
-#ifdef _WINSOCKAPI_
- {
- u_long one = 1;
-
- status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
- }
-#else /* _WINSOCKAPI_ */
-#if defined(VMS)
- {
- int enable = 1;
-
- status = ioctl(s, FIONBIO, &enable);
- }
-#else /* VMS */
-#if defined(__BEOS__) && !defined(__HAIKU__)
- {
- bool noblock = true;
-
- status =
- setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
- sizeof(noblock));
- }
-#else /* __BEOS__ */
- if ((status = fcntl(s, F_GETFL, 0)) != -1) {
-#ifdef O_NONBLOCK
- status |= O_NONBLOCK;
-#else /* O_NONBLOCK */
-#ifdef F_NDELAY
- status |= F_NDELAY;
-#endif /* F_NDELAY */
-#endif /* !O_NONBLOCK */
- status = fcntl(s, F_SETFL, status);
- }
- if (status < 0) {
-#ifdef DEBUG_HTTP
- perror("nonblocking");
-#endif
- __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
- closesocket(s);
- return (-1);
- }
-#endif /* !__BEOS__ */
-#endif /* !VMS */
-#endif /* !_WINSOCKAPI_ */
-
- if (connect(s, addr, addrlen) == -1) {
- switch (socket_errno()) {
- case EINPROGRESS:
- case EWOULDBLOCK:
- break;
- default:
- __xmlIOErr(XML_FROM_HTTP, 0,
- "error connecting to HTTP server");
- closesocket(s);
- return (-1);
- }
- }
-#ifndef HAVE_POLL_H
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4018)
-#endif
-#ifndef _WINSOCKAPI_
- if (s > FD_SETSIZE)
- return -1;
-#endif
- FD_ZERO(&wfd);
- FD_SET(s, &wfd);
-
-#ifdef _WINSOCKAPI_
- FD_ZERO(&xfd);
- FD_SET(s, &xfd);
-
- switch (select(s + 1, NULL, &wfd, &xfd, &tv))
-#else
- switch (select(s + 1, NULL, &wfd, NULL, &tv))
-#endif
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#else /* !HAVE_POLL_H */
- p.fd = s;
- p.events = POLLOUT;
- switch (poll(&p, 1, timeout * 1000))
-#endif /* !HAVE_POLL_H */
-
- {
- case 0:
- /* Time out */
- __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
- closesocket(s);
- return (-1);
- case -1:
- /* Ermm.. ?? */
- __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
- closesocket(s);
- return (-1);
- }
-
-#ifndef HAVE_POLL_H
- if (FD_ISSET(s, &wfd)
-#ifdef _WINSOCKAPI_
- || FD_ISSET(s, &xfd)
-#endif
- )
-#else /* !HAVE_POLL_H */
- if (p.revents == POLLOUT)
-#endif /* !HAVE_POLL_H */
- {
- XML_SOCKLEN_T len;
-
- len = sizeof(status);
-#ifdef SO_ERROR
- if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
- 0) {
- /* Solaris error code */
- __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
- return (-1);
- }
-#endif
- if (status) {
- __xmlIOErr(XML_FROM_HTTP, 0,
- "Error connecting to remote host");
- closesocket(s);
- errno = status;
- return (-1);
- }
- } else {
- /* pbm */
- __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
- closesocket(s);
- return (-1);
- }
-
- return (s);
-}
-
-/**
- * xmlNanoHTTPConnectHost:
- * @host: the host name
- * @port: the port number
- *
- * Attempt a connection to the given host:port endpoint. It tries
- * the multiple IP provided by the DNS if available.
- *
- * Returns -1 in case of failure, the file descriptor number otherwise
- */
-
-static int
-xmlNanoHTTPConnectHost(const char *host, int port)
-{
- struct hostent *h;
- struct sockaddr *addr = NULL;
- struct in_addr ia;
- struct sockaddr_in sockin;
-
-#ifdef SUPPORT_IP6
- struct in6_addr ia6;
- struct sockaddr_in6 sockin6;
-#endif
- int i;
- int s;
-
- memset (&sockin, 0, sizeof(sockin));
-#ifdef SUPPORT_IP6
- memset (&sockin6, 0, sizeof(sockin6));
-#endif
-
-#if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
- if (have_ipv6 ())
- {
- if (!(_res.options & RES_INIT))
- res_init();
- _res.options |= RES_USE_INET6;
- }
-#endif
-
-#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
- if (have_ipv6 ())
-#endif
-#if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
- {
- int status;
- struct addrinfo hints, *res, *result;
-
- result = NULL;
- memset (&hints, 0,sizeof(hints));
- hints.ai_socktype = SOCK_STREAM;
-
- status = getaddrinfo (host, NULL, &hints, &result);
- if (status) {
- __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
- return (-1);
- }
-
- for (res = result; res; res = res->ai_next) {
- if (res->ai_family == AF_INET) {
- if (res->ai_addrlen > sizeof(sockin)) {
- __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
- freeaddrinfo (result);
- return (-1);
- }
- memcpy (&sockin, res->ai_addr, res->ai_addrlen);
- sockin.sin_port = htons (port);
- addr = (struct sockaddr *)&sockin;
-#ifdef SUPPORT_IP6
- } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
- if (res->ai_addrlen > sizeof(sockin6)) {
- __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
- freeaddrinfo (result);
- return (-1);
- }
- memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
- sockin6.sin6_port = htons (port);
- addr = (struct sockaddr *)&sockin6;
-#endif
- } else
- continue; /* for */
-
- s = xmlNanoHTTPConnectAttempt (addr);
- if (s != -1) {
- freeaddrinfo (result);
- return (s);
- }
- }
-
- if (result)
- freeaddrinfo (result);
- }
-#endif
-#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
- else
-#endif
-#if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
- {
- h = gethostbyname (host);
- if (h == NULL) {
-
-/*
- * Okay, I got fed up by the non-portability of this error message
- * extraction code. it work on Linux, if it work on your platform
- * and one want to enable it, send me the defined(foobar) needed
- */
-#if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
- const char *h_err_txt = "";
-
- switch (h_errno) {
- case HOST_NOT_FOUND:
- h_err_txt = "Authoritive host not found";
- break;
-
- case TRY_AGAIN:
- h_err_txt =
- "Non-authoritive host not found or server failure.";
- break;
-
- case NO_RECOVERY:
- h_err_txt =
- "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
- break;
-
- case NO_ADDRESS:
- h_err_txt =
- "Valid name, no data record of requested type.";
- break;
-
- default:
- h_err_txt = "No error text defined.";
- break;
- }
- __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
-#else
- __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
-#endif
- return (-1);
- }
-
- for (i = 0; h->h_addr_list[i]; i++) {
- if (h->h_addrtype == AF_INET) {
- /* A records (IPv4) */
- if ((unsigned int) h->h_length > sizeof(ia)) {
- __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
- return (-1);
- }
- memcpy (&ia, h->h_addr_list[i], h->h_length);
- sockin.sin_family = h->h_addrtype;
- sockin.sin_addr = ia;
- sockin.sin_port = (u_short)htons ((unsigned short)port);
- addr = (struct sockaddr *) &sockin;
-#ifdef SUPPORT_IP6
- } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
- /* AAAA records (IPv6) */
- if ((unsigned int) h->h_length > sizeof(ia6)) {
- __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
- return (-1);
- }
- memcpy (&ia6, h->h_addr_list[i], h->h_length);
- sockin6.sin6_family = h->h_addrtype;
- sockin6.sin6_addr = ia6;
- sockin6.sin6_port = htons (port);
- addr = (struct sockaddr *) &sockin6;
-#endif
- } else
- break; /* for */
-
- s = xmlNanoHTTPConnectAttempt (addr);
- if (s != -1)
- return (s);
- }
- }
-#endif
-
-#ifdef DEBUG_HTTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n",
- host);
-#endif
- return (-1);
-}
-
-
-/**
- * xmlNanoHTTPOpen:
- * @URL: The URL to load
- * @contentType: if available the Content-Type information will be
- * returned at that location
- *
- * This function try to open a connection to the indicated resource
- * via HTTP GET.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- * The contentType, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPOpen(const char *URL, char **contentType) {
- if (contentType != NULL) *contentType = NULL;
- return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
-}
-
-/**
- * xmlNanoHTTPOpenRedir:
- * @URL: The URL to load
- * @contentType: if available the Content-Type information will be
- * returned at that location
- * @redir: if available the redirected URL will be returned
- *
- * This function try to open a connection to the indicated resource
- * via HTTP GET.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- * The contentType, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
- if (contentType != NULL) *contentType = NULL;
- if (redir != NULL) *redir = NULL;
- return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
-}
-
-/**
- * xmlNanoHTTPRead:
- * @ctx: the HTTP context
- * @dest: a buffer
- * @len: the buffer length
- *
- * This function tries to read @len bytes from the existing HTTP connection
- * and saves them in @dest. This is a blocking call.
- *
- * Returns the number of byte read. 0 is an indication of an end of connection.
- * -1 indicates a parameter error.
- */
-int
-xmlNanoHTTPRead(void *ctx, void *dest, int len) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-#ifdef HAVE_ZLIB_H
- int bytes_read = 0;
- int orig_avail_in;
- int z_ret;
-#endif
-
- if (ctx == NULL) return(-1);
- if (dest == NULL) return(-1);
- if (len <= 0) return(0);
-
-#ifdef HAVE_ZLIB_H
- if (ctxt->usesGzip == 1) {
- if (ctxt->strm == NULL) return(0);
-
- ctxt->strm->next_out = dest;
- ctxt->strm->avail_out = len;
- ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
-
- while (ctxt->strm->avail_out > 0 &&
- (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
- orig_avail_in = ctxt->strm->avail_in =
- ctxt->inptr - ctxt->inrptr - bytes_read;
- ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
-
- z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
- bytes_read += orig_avail_in - ctxt->strm->avail_in;
-
- if (z_ret != Z_OK) break;
- }
-
- ctxt->inrptr += bytes_read;
- return(len - ctxt->strm->avail_out);
- }
-#endif
-
- while (ctxt->inptr - ctxt->inrptr < len) {
- if (xmlNanoHTTPRecv(ctxt) <= 0) break;
- }
- if (ctxt->inptr - ctxt->inrptr < len)
- len = ctxt->inptr - ctxt->inrptr;
- memcpy(dest, ctxt->inrptr, len);
- ctxt->inrptr += len;
- return(len);
-}
-
-/**
- * xmlNanoHTTPClose:
- * @ctx: the HTTP context
- *
- * This function closes an HTTP context, it ends up the connection and
- * free all data related to it.
- */
-void
-xmlNanoHTTPClose(void *ctx) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-
- if (ctx == NULL) return;
-
- xmlNanoHTTPFreeCtxt(ctxt);
-}
-
-/**
- * xmlNanoHTTPMethodRedir:
- * @URL: The URL to load
- * @method: the HTTP method to use
- * @input: the input string if any
- * @contentType: the Content-Type information IN and OUT
- * @redir: the redirected URL OUT
- * @headers: the extra headers
- * @ilen: input length
- *
- * This function try to open a connection to the indicated resource
- * via HTTP using the given @method, adding the given extra headers
- * and the input buffer for the request content.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- * The contentType, or redir, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
- char **contentType, char **redir,
- const char *headers, int ilen ) {
- xmlNanoHTTPCtxtPtr ctxt;
- char *bp, *p;
- int blen, ret;
- int nbRedirects = 0;
- char *redirURL = NULL;
-#ifdef DEBUG_HTTP
- int xmt_bytes;
-#endif
-
- if (URL == NULL) return(NULL);
- if (method == NULL) method = "GET";
- xmlNanoHTTPInit();
-
-retry:
- if (redirURL == NULL)
- ctxt = xmlNanoHTTPNewCtxt(URL);
- else {
- ctxt = xmlNanoHTTPNewCtxt(redirURL);
- ctxt->location = xmlMemStrdup(redirURL);
- }
-
- if ( ctxt == NULL ) {
- return ( NULL );
- }
-
- if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
- __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
- xmlNanoHTTPFreeCtxt(ctxt);
- if (redirURL != NULL) xmlFree(redirURL);
- return(NULL);
- }
- if (ctxt->hostname == NULL) {
- __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
- "Failed to identify host in URI");
- xmlNanoHTTPFreeCtxt(ctxt);
- if (redirURL != NULL) xmlFree(redirURL);
- return(NULL);
- }
- if (proxy) {
- blen = strlen(ctxt->hostname) * 2 + 16;
- ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
- }
- else {
- blen = strlen(ctxt->hostname);
- ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
- }
- if (ret < 0) {
- xmlNanoHTTPFreeCtxt(ctxt);
- if (redirURL != NULL) xmlFree(redirURL);
- return(NULL);
- }
- ctxt->fd = ret;
-
- if (input == NULL)
- ilen = 0;
- else
- blen += 36;
-
- if (headers != NULL)
- blen += strlen(headers) + 2;
- if (contentType && *contentType)
- /* reserve for string plus 'Content-Type: \r\n" */
- blen += strlen(*contentType) + 16;
- if (ctxt->query != NULL)
- /* 1 for '?' */
- blen += strlen(ctxt->query) + 1;
- blen += strlen(method) + strlen(ctxt->path) + 24;
-#ifdef HAVE_ZLIB_H
- /* reserve for possible 'Accept-Encoding: gzip' string */
- blen += 23;
-#endif
- if (ctxt->port != 80) {
- /* reserve space for ':xxxxx', incl. potential proxy */
- if (proxy)
- blen += 12;
- else
- blen += 6;
- }
- bp = (char*)xmlMallocAtomic(blen);
- if ( bp == NULL ) {
- xmlNanoHTTPFreeCtxt( ctxt );
- xmlHTTPErrMemory("allocating header buffer");
- return ( NULL );
- }
-
- p = bp;
-
- if (proxy) {
- if (ctxt->port != 80) {
- p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s",
- method, ctxt->hostname,
- ctxt->port, ctxt->path );
- }
- else
- p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
- ctxt->hostname, ctxt->path);
- }
- else
- p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
-
- if (ctxt->query != NULL)
- p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
-
- if (ctxt->port == 80) {
- p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
- ctxt->hostname);
- } else {
- p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
- ctxt->hostname, ctxt->port);
- }
-
-#ifdef HAVE_ZLIB_H
- p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
-#endif
-
- if (contentType != NULL && *contentType)
- p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
-
- if (headers != NULL)
- p += snprintf( p, blen - (p - bp), "%s", headers );
-
- if (input != NULL)
- snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
- else
- snprintf(p, blen - (p - bp), "\r\n");
-
-#ifdef DEBUG_HTTP
- xmlGenericError(xmlGenericErrorContext,
- "-> %s%s", proxy? "(Proxy) " : "", bp);
- if ((blen -= strlen(bp)+1) < 0)
- xmlGenericError(xmlGenericErrorContext,
- "ERROR: overflowed buffer by %d bytes\n", -blen);
-#endif
- ctxt->outptr = ctxt->out = bp;
- ctxt->state = XML_NANO_HTTP_WRITE;
- blen = strlen( ctxt->out );
-#ifdef DEBUG_HTTP
- xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
- if ( xmt_bytes != blen )
- xmlGenericError( xmlGenericErrorContext,
- "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
- xmt_bytes, blen,
- "bytes of HTTP headers sent to host",
- ctxt->hostname );
-#else
- xmlNanoHTTPSend(ctxt, ctxt->out, blen );
-#endif
-
- if ( input != NULL ) {
-#ifdef DEBUG_HTTP
- xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
-
- if ( xmt_bytes != ilen )
- xmlGenericError( xmlGenericErrorContext,
- "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
- xmt_bytes, ilen,
- "bytes of HTTP content sent to host",
- ctxt->hostname );
-#else
- xmlNanoHTTPSend( ctxt, input, ilen );
-#endif
- }
-
- ctxt->state = XML_NANO_HTTP_READ;
-
- while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
- if (*p == 0) {
- ctxt->content = ctxt->inrptr;
- xmlFree(p);
- break;
- }
- xmlNanoHTTPScanAnswer(ctxt, p);
-
-#ifdef DEBUG_HTTP
- xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
-#endif
- xmlFree(p);
- }
-
- if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
- (ctxt->returnValue < 400)) {
-#ifdef DEBUG_HTTP
- xmlGenericError(xmlGenericErrorContext,
- "\nRedirect to: %s\n", ctxt->location);
-#endif
- while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
- if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
- nbRedirects++;
- if (redirURL != NULL)
- xmlFree(redirURL);
- redirURL = xmlMemStrdup(ctxt->location);
- xmlNanoHTTPFreeCtxt(ctxt);
- goto retry;
- }
- xmlNanoHTTPFreeCtxt(ctxt);
- if (redirURL != NULL) xmlFree(redirURL);
-#ifdef DEBUG_HTTP
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
-#endif
- return(NULL);
- }
-
- if (contentType != NULL) {
- if (ctxt->contentType != NULL)
- *contentType = xmlMemStrdup(ctxt->contentType);
- else
- *contentType = NULL;
- }
-
- if ((redir != NULL) && (redirURL != NULL)) {
- *redir = redirURL;
- } else {
- if (redirURL != NULL)
- xmlFree(redirURL);
- if (redir != NULL)
- *redir = NULL;
- }
-
-#ifdef DEBUG_HTTP
- if (ctxt->contentType != NULL)
- xmlGenericError(xmlGenericErrorContext,
- "\nCode %d, content-type '%s'\n\n",
- ctxt->returnValue, ctxt->contentType);
- else
- xmlGenericError(xmlGenericErrorContext,
- "\nCode %d, no content-type\n\n",
- ctxt->returnValue);
-#endif
-
- return((void *) ctxt);
-}
-
-/**
- * xmlNanoHTTPMethod:
- * @URL: The URL to load
- * @method: the HTTP method to use
- * @input: the input string if any
- * @contentType: the Content-Type information IN and OUT
- * @headers: the extra headers
- * @ilen: input length
- *
- * This function try to open a connection to the indicated resource
- * via HTTP using the given @method, adding the given extra headers
- * and the input buffer for the request content.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- * The contentType, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
- char **contentType, const char *headers, int ilen) {
- return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
- NULL, headers, ilen));
-}
-
-/**
- * xmlNanoHTTPFetch:
- * @URL: The URL to load
- * @filename: the filename where the content should be saved
- * @contentType: if available the Content-Type information will be
- * returned at that location
- *
- * This function try to fetch the indicated resource via HTTP GET
- * and save it's content in the file.
- *
- * Returns -1 in case of failure, 0 incase of success. The contentType,
- * if provided must be freed by the caller
- */
-int
-xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
- void *ctxt = NULL;
- char *buf = NULL;
- int fd;
- int len;
-
- if (filename == NULL) return(-1);
- ctxt = xmlNanoHTTPOpen(URL, contentType);
- if (ctxt == NULL) return(-1);
-
- if (!strcmp(filename, "-"))
- fd = 0;
- else {
- fd = open(filename, O_CREAT | O_WRONLY, 00644);
- if (fd < 0) {
- xmlNanoHTTPClose(ctxt);
- if ((contentType != NULL) && (*contentType != NULL)) {
- xmlFree(*contentType);
- *contentType = NULL;
- }
- return(-1);
- }
- }
-
- xmlNanoHTTPFetchContent( ctxt, &buf, &len );
- if ( len > 0 ) {
- write(fd, buf, len);
- }
-
- xmlNanoHTTPClose(ctxt);
- close(fd);
- return(0);
-}
-
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlNanoHTTPSave:
- * @ctxt: the HTTP context
- * @filename: the filename where the content should be saved
- *
- * This function saves the output of the HTTP transaction to a file
- * It closes and free the context at the end
- *
- * Returns -1 in case of failure, 0 incase of success.
- */
-int
-xmlNanoHTTPSave(void *ctxt, const char *filename) {
- char *buf = NULL;
- int fd;
- int len;
-
- if ((ctxt == NULL) || (filename == NULL)) return(-1);
-
- if (!strcmp(filename, "-"))
- fd = 0;
- else {
- fd = open(filename, O_CREAT | O_WRONLY, 0666);
- if (fd < 0) {
- xmlNanoHTTPClose(ctxt);
- return(-1);
- }
- }
-
- xmlNanoHTTPFetchContent( ctxt, &buf, &len );
- if ( len > 0 ) {
- write(fd, buf, len);
- }
-
- xmlNanoHTTPClose(ctxt);
- close(fd);
- return(0);
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
-/**
- * xmlNanoHTTPReturnCode:
- * @ctx: the HTTP context
- *
- * Get the latest HTTP return code received
- *
- * Returns the HTTP return code for the request.
- */
-int
-xmlNanoHTTPReturnCode(void *ctx) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-
- if (ctxt == NULL) return(-1);
-
- return(ctxt->returnValue);
-}
-
-/**
- * xmlNanoHTTPAuthHeader:
- * @ctx: the HTTP context
- *
- * Get the authentication header of an HTTP context
- *
- * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
- * header.
- */
-const char *
-xmlNanoHTTPAuthHeader(void *ctx) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-
- if (ctxt == NULL) return(NULL);
-
- return(ctxt->authHeader);
-}
-
-/**
- * xmlNanoHTTPContentLength:
- * @ctx: the HTTP context
- *
- * Provides the specified content length from the HTTP header.
- *
- * Return the specified content length from the HTTP header. Note that
- * a value of -1 indicates that the content length element was not included in
- * the response header.
- */
-int
-xmlNanoHTTPContentLength( void * ctx ) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
- return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
-}
-
-/**
- * xmlNanoHTTPRedir:
- * @ctx: the HTTP context
- *
- * Provides the specified redirection URL if available from the HTTP header.
- *
- * Return the specified redirection URL or NULL if not redirected.
- */
-const char *
-xmlNanoHTTPRedir( void * ctx ) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
- return ( ( ctxt == NULL ) ? NULL : ctxt->location );
-}
-
-/**
- * xmlNanoHTTPEncoding:
- * @ctx: the HTTP context
- *
- * Provides the specified encoding if specified in the HTTP headers.
- *
- * Return the specified encoding or NULL if not available
- */
-const char *
-xmlNanoHTTPEncoding( void * ctx ) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
- return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
-}
-
-/**
- * xmlNanoHTTPMimeType:
- * @ctx: the HTTP context
- *
- * Provides the specified Mime-Type if specified in the HTTP headers.
- *
- * Return the specified Mime-Type or NULL if not available
- */
-const char *
-xmlNanoHTTPMimeType( void * ctx ) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
- return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
-}
-
-/**
- * xmlNanoHTTPFetchContent:
- * @ctx: the HTTP context
- * @ptr: pointer to set to the content buffer.
- * @len: integer pointer to hold the length of the content
- *
- * Check if all the content was read
- *
- * Returns 0 if all the content was read and available, returns
- * -1 if received content length was less than specified or an error
- * occurred.
- */
-static int
-xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
- xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
- int rc = 0;
- int cur_lgth;
- int rcvd_lgth;
- int dummy_int;
- char * dummy_ptr = NULL;
-
- /* Dummy up return input parameters if not provided */
-
- if ( len == NULL )
- len = &dummy_int;
-
- if ( ptr == NULL )
- ptr = &dummy_ptr;
-
- /* But can't work without the context pointer */
-
- if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
- *len = 0;
- *ptr = NULL;
- return ( -1 );
- }
-
- rcvd_lgth = ctxt->inptr - ctxt->content;
-
- while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
-
- rcvd_lgth += cur_lgth;
- if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
- break;
- }
-
- *ptr = ctxt->content;
- *len = rcvd_lgth;
-
- if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
- rc = -1;
- else if ( rcvd_lgth == 0 )
- rc = -1;
-
- return ( rc );
-}
-
-#ifdef STANDALONE
-int main(int argc, char **argv) {
- char *contentType = NULL;
-
- if (argv[1] != NULL) {
- if (argv[2] != NULL)
- xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
- else
- xmlNanoHTTPFetch(argv[1], "-", &contentType);
- if (contentType != NULL) xmlFree(contentType);
- } else {
- xmlGenericError(xmlGenericErrorContext,
- "%s: minimal HTTP GET implementation\n", argv[0]);
- xmlGenericError(xmlGenericErrorContext,
- "\tusage %s [ URL [ filename ] ]\n", argv[0]);
- }
- xmlNanoHTTPCleanup();
- xmlMemoryDump();
- return(0);
-}
-#endif /* STANDALONE */
-#else /* !LIBXML_HTTP_ENABLED */
-#ifdef STANDALONE
-#include <stdio.h>
-int main(int argc, char **argv) {
- xmlGenericError(xmlGenericErrorContext,
- "%s : HTTP support not compiled in\n", argv[0]);
- return(0);
-}
-#endif /* STANDALONE */
-#endif /* LIBXML_HTTP_ENABLED */
-#define bottom_nanohttp
-#include "elfgcchack.h"
diff --git a/third_party/libxml/src/xmlIO.c b/third_party/libxml/src/xmlIO.c
index 8fc00e3..29623dc 100644
--- a/third_party/libxml/src/xmlIO.c
+++ b/third_party/libxml/src/xmlIO.c
@@ -85,8 +85,6 @@
#include <libxml/parserInternals.h>
#include <libxml/xmlIO.h>
#include <libxml/uri.h>
-#include <libxml/nanohttp.h>
-#include <libxml/nanoftp.h>
#include <libxml/xmlerror.h>
#ifdef LIBXML_CATALOG_ENABLED
#include <libxml/catalog.h>
diff --git a/third_party/libxml/win32/include/libxml/xmlversion.h b/third_party/libxml/win32/include/libxml/xmlversion.h
index 3753baf..90f38d5 100644
--- a/third_party/libxml/win32/include/libxml/xmlversion.h
+++ b/third_party/libxml/win32/include/libxml/xmlversion.h
@@ -165,7 +165,7 @@
*
* Whether the FTP support is configured in
*/
-#if 1
+#if 0
#define LIBXML_FTP_ENABLED
#endif
@@ -174,7 +174,7 @@
*
* Whether the HTTP support is configured in
*/
-#if 1
+#if 0
#define LIBXML_HTTP_ENABLED
#endif
diff --git a/third_party/re2/patches/re2-libcxx.patch b/third_party/re2/patches/re2-libcxx.patch
index fc4dd1c..54f3b6b 100644
--- a/third_party/re2/patches/re2-libcxx.patch
+++ b/third_party/re2/patches/re2-libcxx.patch
@@ -12,3 +12,12 @@
#include <tr1/unordered_set>
using std::tr1::unordered_set;
+@@ -54,1 +55,1 @@ using std::tr1::unordered_set;
+ #else
+
+ #include <unordered_set>
+-#if defined(WIN32) || defined(OS_ANDROID)
++#if defined(WIN32) || (defined(OS_ANDROID) && !defined(_LIBCPP_ABI_VERSION))
+ using std::tr1::unordered_set;
+ #else
+ using std::unordered_set;
\ No newline at end of file
diff --git a/third_party/re2/util/util.h b/third_party/re2/util/util.h
index 8350445..4f0fdb8 100644
--- a/third_party/re2/util/util.h
+++ b/third_party/re2/util/util.h
@@ -55,7 +55,7 @@
#else
#include <unordered_set>
-#if defined(WIN32) || defined(OS_ANDROID)
+#if defined(WIN32) || (defined(OS_ANDROID) && !defined(_LIBCPP_ABI_VERSION))
using std::tr1::unordered_set;
#else
using std::unordered_set;
diff --git a/tools/android/md5sum/md5sum.cc b/tools/android/md5sum/md5sum.cc
index 07ce2c2..a204569 100644
--- a/tools/android/md5sum/md5sum.cc
+++ b/tools/android/md5sum/md5sum.cc
@@ -18,25 +18,21 @@
namespace {
-const int kBufferSize = 1024;
-
// Returns whether |path|'s MD5 was successfully written to |digest_string|.
bool MD5Sum(const char* path, std::string* digest_string) {
- std::ifstream stream(path);
- if (!stream.good()) {
+ base::ScopedFILE file(fopen(path, "rb"));
+ if (!file) {
LOG(ERROR) << "Could not open file " << path;
return false;
}
base::MD5Context ctx;
base::MD5Init(&ctx);
- char buf[kBufferSize];
- while (stream.good()) {
- std::streamsize bytes_read = stream.readsome(buf, sizeof(buf));
- if (bytes_read == 0)
- break;
- base::MD5Update(&ctx, base::StringPiece(buf, bytes_read));
- }
- if (stream.fail()) {
+ const size_t kBufferSize = 1 << 16;
+ scoped_ptr<char[]> buf(new char[kBufferSize]);
+ size_t len;
+ while ((len = fread(buf.get(), 1, kBufferSize, file.get())) > 0)
+ base::MD5Update(&ctx, base::StringPiece(buf.get(), len));
+ if (ferror(file.get())) {
LOG(ERROR) << "Error reading file " << path;
return false;
}
diff --git a/tools/android/run_pie/run_pie.gyp b/tools/android/run_pie/run_pie.gyp
index b713dc4..75850f4 100644
--- a/tools/android/run_pie/run_pie.gyp
+++ b/tools/android/run_pie/run_pie.gyp
@@ -18,10 +18,10 @@
'ldflags!': [
'-pie',
],
- # Don't inherit unneeded dependencies on stlport.so, so the binary remains
+ # Don't inherit unneeded dependencies on libc++, so the binary remains
# self-contained also in component=shared_library builds.
'libraries!': [
- '-l<(android_stlport_library)',
+ '-l<(android_libcpp_library)',
],
},
{
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp
index 931da02..6a4233a 100644
--- a/tools/clang/plugins/ChromeClassTester.cpp
+++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -18,6 +18,7 @@
#endif
using namespace clang;
+using chrome_checker::Options;
namespace {
@@ -30,8 +31,10 @@
} // namespace
-ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
- : instance_(instance),
+ChromeClassTester::ChromeClassTester(CompilerInstance& instance,
+ const Options& options)
+ : options_(options),
+ instance_(instance),
diagnostic_(instance.getDiagnostics()) {
BuildBannedLists();
}
@@ -95,16 +98,13 @@
std::string err;
err = "[chromium-style] ";
err += raw_error;
- // TODO(dcheng): Re-enable -Werror for these diagnostics on Windows once all
- // the pre-existing warnings are cleaned up. https://crbug.com/467287
- DiagnosticIDs::Level level =
-#if !defined(LLVM_ON_WIN32)
- diagnostic().getWarningsAsErrors() ?
- DiagnosticIDs::Error :
-#endif
- DiagnosticIDs::Warning;
+
+ DiagnosticIDs::Level level = getErrorLevel() == DiagnosticsEngine::Error
+ ? DiagnosticIDs::Error : DiagnosticIDs::Warning;
+
unsigned id = diagnostic().getDiagnosticIDs()->getCustomDiagID(level, err);
DiagnosticBuilder builder = diagnostic().Report(full, id);
+
}
bool ChromeClassTester::InBannedDirectory(SourceLocation loc) {
@@ -130,9 +130,7 @@
}
#if defined(LLVM_ON_UNIX)
- // We need to munge the paths so that they are relative to the repository
- // srcroot. We first resolve the symlinktastic relative path and then
- // remove our known srcroot from it if needed.
+ // Resolve the symlinktastic relative path and make it absolute.
char resolvedPath[MAXPATHLEN];
if (realpath(filename.c_str(), resolvedPath)) {
filename = resolvedPath;
@@ -141,6 +139,15 @@
#if defined(LLVM_ON_WIN32)
std::replace(filename.begin(), filename.end(), '\\', '/');
+
+ // On Posix, realpath() has made the path absolute. On Windows, this isn't
+ // necessarily true, so prepend a '/' to the path to make sure the
+ // banned_directories_ loop below works correctly.
+ // This turns e.g. "gen/dir/file.cc" to "/gen/dir/file.cc" which lets the
+ // "/gen/" banned_dir work.
+ // This seems simpler than converting to utf16, calling GetFullPathNameW(),
+ // and converting back to utf8.
+ filename.insert(filename.begin(), '/');
#endif
for (const std::string& banned_dir : banned_directories_) {
@@ -304,3 +311,11 @@
*filename = ploc.getFilename();
return true;
}
+
+DiagnosticsEngine::Level ChromeClassTester::getErrorLevel() {
+ if (options_.warn_only)
+ return DiagnosticsEngine::Warning;
+
+ return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error
+ : DiagnosticsEngine::Warning;
+}
diff --git a/tools/clang/plugins/ChromeClassTester.h b/tools/clang/plugins/ChromeClassTester.h
index ed65050..6b5cdf3 100644
--- a/tools/clang/plugins/ChromeClassTester.h
+++ b/tools/clang/plugins/ChromeClassTester.h
@@ -8,6 +8,7 @@
#include <set>
#include <vector>
+#include "Options.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -16,7 +17,8 @@
// headers to subclasses which implement CheckChromeClass().
class ChromeClassTester : public clang::ASTConsumer {
public:
- explicit ChromeClassTester(clang::CompilerInstance& instance);
+ ChromeClassTester(clang::CompilerInstance& instance,
+ const chrome_checker::Options& options);
virtual ~ChromeClassTester();
// clang::ASTConsumer:
@@ -25,6 +27,8 @@
void CheckTag(clang::TagDecl*);
+ clang::DiagnosticsEngine::Level getErrorLevel();
+
protected:
clang::CompilerInstance& instance() { return instance_; }
clang::DiagnosticsEngine& diagnostic() { return diagnostic_; }
@@ -50,6 +54,9 @@
// implementation (.cc, .cpp, .mm) file.
bool InImplementationFile(clang::SourceLocation location);
+ // Options.
+ const chrome_checker::Options options_;
+
private:
void BuildBannedLists();
diff --git a/tools/clang/plugins/FindBadConstructsAction.cpp b/tools/clang/plugins/FindBadConstructsAction.cpp
index 6c39d72..8125084 100644
--- a/tools/clang/plugins/FindBadConstructsAction.cpp
+++ b/tools/clang/plugins/FindBadConstructsAction.cpp
@@ -57,6 +57,8 @@
options_.with_ast_visitor = true;
} else if (args[i] == "check-templates") {
options_.check_templates = true;
+ } else if (args[i] == "warn-only") {
+ options_.warn_only = true;
} else {
parsed = false;
llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n";
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.cpp b/tools/clang/plugins/FindBadConstructsConsumer.cpp
index 20919a4..4dc305e 100644
--- a/tools/clang/plugins/FindBadConstructsConsumer.cpp
+++ b/tools/clang/plugins/FindBadConstructsConsumer.cpp
@@ -101,7 +101,7 @@
FindBadConstructsConsumer::FindBadConstructsConsumer(CompilerInstance& instance,
const Options& options)
- : ChromeClassTester(instance), options_(options) {
+ : ChromeClassTester(instance, options) {
// Messages for virtual method specifiers.
diag_method_requires_override_ =
diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresOverride);
@@ -593,19 +593,6 @@
return None;
}
-// Adds either a warning or error, based on the current handling of
-// -Werror.
-DiagnosticsEngine::Level FindBadConstructsConsumer::getErrorLevel() {
-#if defined(LLVM_ON_WIN32)
- // TODO(dcheng): Re-enable -Werror for these diagnostics on Windows once all
- // the pre-existing warnings are cleaned up. https://crbug.com/467287
- return DiagnosticsEngine::Warning;
-#else
- return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error
- : DiagnosticsEngine::Warning;
-#endif
-}
-
// Returns true if |base| specifies one of the Chromium reference counted
// classes (base::RefCounted / base::RefCountedThreadSafe).
bool FindBadConstructsConsumer::IsRefCountedCallback(
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.h b/tools/clang/plugins/FindBadConstructsConsumer.h
index 6e2b2c9..c52a8f3 100644
--- a/tools/clang/plugins/FindBadConstructsConsumer.h
+++ b/tools/clang/plugins/FindBadConstructsConsumer.h
@@ -71,7 +71,6 @@
static RefcountIssue CheckRecordForRefcountIssue(
const clang::CXXRecordDecl* record,
clang::SourceLocation& loc);
- clang::DiagnosticsEngine::Level getErrorLevel();
static bool IsRefCountedCallback(const clang::CXXBaseSpecifier* base,
clang::CXXBasePath& path,
void* user_data);
@@ -86,8 +85,6 @@
void CheckWeakPtrFactoryMembers(clang::SourceLocation record_location,
clang::CXXRecordDecl* record);
- const Options options_;
-
unsigned diag_method_requires_override_;
unsigned diag_redundant_virtual_specifier_;
unsigned diag_base_method_virtual_and_final_;
diff --git a/tools/clang/plugins/Options.h b/tools/clang/plugins/Options.h
index 112ec10..5131905 100644
--- a/tools/clang/plugins/Options.h
+++ b/tools/clang/plugins/Options.h
@@ -12,12 +12,14 @@
: check_base_classes(false),
check_enum_last_value(false),
with_ast_visitor(false),
- check_templates(false) {}
+ check_templates(false),
+ warn_only(false) {}
bool check_base_classes;
bool check_enum_last_value;
bool with_ast_visitor;
bool check_templates;
+ bool warn_only;
};
} // namespace chrome_checker
diff --git a/tools/clang/plugins/tests/warn_only.cpp b/tools/clang/plugins/tests/warn_only.cpp
new file mode 100644
index 0000000..1fbefcb
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.cpp
@@ -0,0 +1,5 @@
+// Copyright (c) 2015 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 "warn_only.h"
diff --git a/tools/clang/plugins/tests/warn_only.flags b/tools/clang/plugins/tests/warn_only.flags
new file mode 100644
index 0000000..01e7b3b
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.flags
@@ -0,0 +1 @@
+-Werror -Xclang -plugin-arg-find-bad-constructs -Xclang warn-only
diff --git a/tools/clang/plugins/tests/warn_only.h b/tools/clang/plugins/tests/warn_only.h
new file mode 100644
index 0000000..fcc0aa1
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2015 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 WARN_ONLY_H_
+#define WARN_ONLY_H_
+
+#include <string>
+#include <vector>
+
+class InlineCtors {
+ public:
+ InlineCtors() {}
+ ~InlineCtors() {}
+
+ private:
+ std::vector<int> one_;
+ std::vector<std::string> two_;
+};
+
+#endif // WARN_ONLY_H_
diff --git a/tools/clang/plugins/tests/warn_only.txt b/tools/clang/plugins/tests/warn_only.txt
new file mode 100644
index 0000000..4b5c2d0
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.txt
@@ -0,0 +1,8 @@
+In file included from warn_only.cpp:5:
+./warn_only.h:13:3: warning: [chromium-style] Complex constructor has an inlined body.
+ InlineCtors() {}
+ ^
+./warn_only.h:14:3: warning: [chromium-style] Complex destructor has an inline body.
+ ~InlineCtors() {}
+ ^
+2 warnings generated.
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 30d9ce9..9bb306d 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -25,7 +25,7 @@
# in bringup. Use a pinned revision to make it slightly more stable.
if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and
not 'LLVM_FORCE_HEAD_REVISION' in os.environ):
- LLVM_WIN_REVISION = '235793'
+ LLVM_WIN_REVISION = '235968'
# Path constants. (All of these should be absolute paths.)
THIS_DIR = os.path.abspath(os.path.dirname(__file__))
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh
index f0dbeb0..dd6f089 100755
--- a/tools/clang/scripts/update.sh
+++ b/tools/clang/scripts/update.sh
@@ -665,7 +665,7 @@
--platform=android-14 \
--install-dir="${LLVM_BUILD_DIR}/android-toolchain" \
--system=linux-x86_64 \
- --stl=stlport \
+ --stl=libcxx \
--toolchain=arm-linux-androideabi-4.9
# Android NDK r9d copies a broken unwind.h into the toolchain, see
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index d56ba05..6c353d2 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -218,6 +218,9 @@
"ui/file_manager/file_manager_resources.grd": {
"includes": [28100],
},
+ "components/chrome_apps/chrome_apps_resources.grd": {
+ "includes": [28250],
+ },
"ui/login/login_resources.grd": {
"includes": [28300],
},
diff --git a/tools/valgrind/OWNERS b/tools/valgrind/OWNERS
index 73ce47c..e1a653b 100644
--- a/tools/valgrind/OWNERS
+++ b/tools/valgrind/OWNERS
@@ -2,4 +2,3 @@
bruening@chromium.org
glider@chromium.org
thestig@chromium.org
-timurrrr@chromium.org
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index e8074f3..571beb1 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -401,6 +401,9 @@
def TestMessageCenter(self):
return self.SimpleTest("message_center", "message_center_unittests")
+ def TestMidi(self):
+ return self.SimpleTest("chrome", "midi_unittests")
+
def TestMojoCommon(self):
return self.SimpleTest("mojo_common", "mojo_common_unittests")
@@ -696,6 +699,7 @@
"media": TestMedia, "media_unittests": TestMedia,
"message_center": TestMessageCenter,
"message_center_unittests" : TestMessageCenter,
+ "midi": TestMidi, "midi_unittests": TestMidi,
"mojo_common": TestMojoCommon,
"mojo_system": TestMojoSystem,
"mojo_public_system": TestMojoPublicSystem,
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index e54404b..ec87454 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -774,3 +774,29 @@
*!cc::LayerTreeHost::BeginMainFrame
*!cc::ThreadProxy::BeginMainFrame
*!base::internal::InvokeHelper<>::MakeItSo
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/483305
+blink_web.dll!blink::WebFrameWidgetImpl::suppressInvalidations
+blink_web.dll!blink::WebFrameWidgetImpl::setRootGraphicsLayer
+blink_web.dll!blink::ChromeClientImpl::attachRootGraphicsLayer
+blink_web.dll!blink::DeprecatedPaintLayerCompositor::detachRootLayer
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/483305b
+blink_web.dll!blink::WebFrameWidgetImpl::setRootGraphicsLayer
+blink_web.dll!blink::ChromeClientImpl::attachRootGraphicsLayer
+blink_web.dll!blink::DeprecatedPaintLayerCompositor::detachRootLayer
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/484352
+blink_web.dll!blink::WebFrameWidgetImpl::setIsAcceleratedCompositingActive
+blink_web.dll!blink::WebFrameWidgetImpl::willCloseLayerTreeView
+scheduler.dll!scheduler::TaskQueueManager::ProcessTaskFromWorkQueue
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/484352b
+blink_web.dll!blink::WebFrameWidgetImpl::setIsAcceleratedCompositingActive
+blink_web.dll!blink::WebFrameWidgetImpl::setRootGraphicsLayer
+blink_web.dll!blink::ChromeClientImpl::attachRootGraphicsLayer
+blink_web.dll!blink::DeprecatedPaintLayerCompositor::detachRootLayer
diff --git a/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt
index ec243c5..82f3f9c 100644
--- a/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt
@@ -37,4 +37,4 @@
MessageLoopTestTypeUI.RecursiveDenial3
# https://crbug.com/481231
-WinHeapDumpProviderTest.DumpInto
+WinHeapDumpProviderTest.OnMemoryDump
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
index b5e2b57..69db506 100644
--- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
@@ -9,9 +9,6 @@
# http://crbug.com/450221
ProfileChooserViewExtensionsTest.LockProfileNoBlockOtherProfileExtensions
-# http://crbug.com/467514
-AsyncExtensionSettingsWebUITest.testErrorListButtonVisibility
-
# it takes too long to run all browser_tests with Dr.Memory,
# and we only select subset to run
# A*
diff --git a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt
index 55df649..cb3deed 100644
--- a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt
+++ b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt
@@ -39,3 +39,9 @@
# http://crbug.com/470507
SRC_ClearKey/EncryptedMediaTest.Playback_VideoClearAudio_WebM/0
+
+# http://crbug.com/484351
+PluginTest.VerifyPluginWindowRect
+
+# http://crbug.com/484852
+PluginTest.NPObjectIdentity
diff --git a/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt b/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt
index 56bb83c..a986378 100644
--- a/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt
@@ -1,3 +1,4 @@
# Fails http://crbug.com/256911
MessageCenterImplTest.PopupTimersControllerResetTimer
+MessageCenterImplTest.PopupTimersControllerStartMultipleTimers
MessageCenterImplTest.PopupTimersControllerStartMultipleTimersPause
diff --git a/tools/valgrind/gtest_exclude/mojo_application_manager_unittests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/mojo_application_manager_unittests.gtest-drmemory.txt
deleted file mode 100644
index bb80765..0000000
--- a/tools/valgrind/gtest_exclude/mojo_application_manager_unittests.gtest-drmemory.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# http://crbug.com/416620
-ApplicationManagerTest.*
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
index a43a673..371ea3f 100644
--- a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
+++ b/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
@@ -32,3 +32,6 @@
# http://crbug.com/403533
ExtensionPathUtilTest.BasicPrettifyPathTest
+
+# http://crbug.com/483642
+MultiUserWindowManagerChromeOSTest.FullUserSwitchAnimationTests
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 56948ef..581dd99 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -511,6 +511,15 @@
fun:_ZN7content18ManifestParserTest13ParseManifestERKN4base16BasicStringPieceISsEE
fun:_ZN7content45ManifestParserTest_IconDensityParseRules_Test8TestBodyEv
}
+{
+ bug_484444
+ Memcheck:Leak
+ fun:_Znw*
+ ...
+ fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEPK15MojoAsyncWaiter
+ fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16InterfaceRequestIS1_EEPK15MojoAsyncWaiter
+ fun:_ZN7content19ServiceRegistryImpl4BindEN4mojo16InterfaceRequestINS1_15ServiceProviderEEE
+}
#-----------------------------------------------------------------------
# 3. Suppressions for real chromium bugs that are not yet fixed.
@@ -946,27 +955,6 @@
fun:*DownloadFileTest5SetUpEv
}
{
- bug_72544
- Memcheck:Leak
- fun:malloc
- fun:_ZN3WTF10fastMallocEj
- fun:_ZN3WTF10RefCountedIN7blink14StyleSheetListEEnwEj
- fun:_ZN5blink14StyleSheetList6createEPNS_8DocumentE
- fun:_ZN5blink8DocumentC2EPNS_5FrameERKNS_4KURLEbbS5_
- fun:_ZN5blink12HTMLDocumentC1EPNS_5FrameERKNS_4KURLES5_
- fun:_ZN5blink12HTMLDocument6createEPNS_5FrameERKNS_4KURLES5_
- fun:_ZN5blink17DOMImplementation14createDocumentERKN3WTF6StringEPNS_5FrameERKNS_4KURLEb
- fun:_ZN5blink14DocumentWriter14createDocumentERKNS_4KURLE
- fun:_ZN5blink14DocumentWriter5beginERKNS_4KURLEbPNS_14SecurityOriginE
- fun:_ZN5blink11FrameLoader4initEv
- fun:_ZN5blink5Frame4initEv
- fun:_ZN5blink12WebFrameImpl21initializeAsMainFrameEPNS_11WebViewImplE
- fun:_ZN5blink11WebViewImpl19initializeMainFrameEPNS_14WebFrameClientE
- fun:_ZN10RenderViewC1EP16RenderThreadBaseiiRK19RendererPreferencesRK14WebPreferencesPN4base14RefCountedDataIiEEixRKSbItNS8_20string16_char_traitsESaItEE
- fun:_ZN10RenderView6CreateEP16RenderThreadBaseiiRK19RendererPreferencesRK14WebPreferencesPN4base14RefCountedDataIiEEixRKSbItNS8_20string16_char_traitsESaItEE
- fun:_ZN12RenderThread15OnCreateNewViewERK18ViewMsg_New_Params
-}
-{
bug_72698_a
Memcheck:Leak
fun:_Znw*
@@ -1823,16 +1811,6 @@
fun:ChromeMain
}
{
- bug_164178
- Memcheck:Leak
- fun:_Znw*
- fun:_ZN3net25MultiThreadedCertVerifier6VerifyEPNS_15X509CertificateERKSsiPNS_6CRLSetEPNS_16CertVerifyResultERKN4base8CallbackIFviEEEPPvRKNS_11BoundNetLogE
- fun:_ZN3net25SingleRequestCertVerifier6VerifyEPNS_15X509CertificateERKSsiPNS_6CRLSetEPNS_16CertVerifyResultERKN4base8CallbackIFviEEERKNS_11BoundNetLogE
- fun:_ZN3net18SSLClientSocketNSS12DoVerifyCertEi
- fun:_ZN3net18SSLClientSocketNSS15DoHandshakeLoopEi
- fun:_ZN3net18SSLClientSocketNSS21OnHandshakeIOCompleteEi
-}
-{
bug_164179
Memcheck:Leak
fun:_Znw*
@@ -2663,7 +2641,7 @@
bug_364724b
Memcheck:Uninitialized
fun:_ZN4base17MD5DigestToBase16ERKNS_9MD5DigestE
- fun:_ZN7content16WebKitTestRunner17CaptureDumpPixelsERK8SkBitmap
+ fun:_ZN7content15BlinkTestRunner17CaptureDumpPixelsERK8SkBitmap
}
{
bug_364724c
@@ -2680,7 +2658,7 @@
fun:malloc
fun:_ZN3WTF10fastMallocEm
fun:_ZN3WTF10RefCountedIN5blink11ScriptStateEEnwEm
- fun:_ZN5blink11ScriptState6createEN2v86HandleINS1_7ContextEEEN3WTF10PassRefPtrINS_15DOMWrapperWorldEEE
+ fun:_ZN5blink11ScriptState6createEN2v85LocalINS1_7ContextEEEN3WTF10PassRefPtrINS_15DOMWrapperWorldEEE
...
fun:_ZN3WTF15FunctionWrapperIMN5blink12WorkerThreadEFvvEEclEPS2_
}
@@ -3121,7 +3099,7 @@
fun:_ZN2v86Object3SetENS_6HandleINS_5ValueEEES3_
fun:_ZN18WebCoreTestSupport21injectInternalsObjectEN2v85LocalINS0_7ContextEEE
fun:_ZN5blink17WebTestingSupport21injectInternalsObjectEPNS_13WebLocalFrameE
- fun:_ZN7content16WebKitTestRunner20DidClearWindowObjectEPN5blink13WebLocalFrameE
+ fun:_ZN7content15BlinkTestRunner20DidClearWindowObjectEPN5blink13WebLocalFrameE
fun:_ZN7content14RenderViewImpl20didClearWindowObjectEPN5blink13WebLocalFrameE
fun:_ZN7content15RenderFrameImpl20didClearWindowObjectEPN5blink13WebLocalFrameE
fun:_ZThn16_N7content15RenderFrameImpl20didClearWindowObjectEPN5blink13WebLocalFrameE
@@ -3131,7 +3109,7 @@
fun:_ZN5blink11toV8ContextEPNS_10LocalFrameERNS_15DOMWrapperWorldE
fun:_ZNK5blink17WebLocalFrameImpl22mainWorldScriptContextEv
fun:_ZN5blink17WebTestingSupport20resetInternalsObjectEPNS_13WebLocalFrameE
- fun:_ZN7content16WebKitTestRunner5ResetEv
+ fun:_ZN7content15BlinkTestRunner5ResetEv
fun:_ZN7content26ShellContentRendererClient17RenderViewCreatedEPNS_10RenderViewE
fun:_ZN7content14RenderViewImpl10InitializeEPNS_20RenderViewImplParamsE
fun:_ZN7content14RenderViewImpl6CreateEibRKNS_19RendererPreferencesERKNS_14WebPreferencesEiiilRKSbItN4base20string16_char_traitsESaItEEbbibbiRKN5blink13WebScreenInfoE17AccessibilityMode
@@ -3242,17 +3220,6 @@
fun:_ZN8app_list4test12_GLOBAL__N_122AppListViewTestContext16RunStartPageTestEv
}
{
- bug_405865
- Memcheck:Uninitialized
- fun:_ZNK5blink13InlineFlowBox20computeMaxLogicalTopERf
- ...
- fun:_ZNK5blink13RootInlineBox13maxLogicalTopEv
- fun:_ZN5blinkL22computeUnderlineOffsetENS_21TextUnderlinePositionERKNS_11FontMetricsEPKNS_13InlineTextBoxEf
- fun:_ZN5blink20InlineTextBoxPainter15paintDecorationEPNS_15GraphicsContextERKNS_10FloatPointENS_14TextDecorationE
- fun:_ZN5blink20InlineTextBoxPainter5paintERNS_9PaintInfoERKNS_11LayoutPointE
- fun:_ZN5blink13InlineTextBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-}
-{
bug_415092
Memcheck:Leak
fun:_Znw*
@@ -3276,44 +3243,6 @@
fun:_ZN7content17BlinkPlatformImpl9DoTimeoutEv
}
{
- bug_417048a
- Memcheck:Uninitialized
- ...
- fun:_ZNK5blink17RenderLineBoxList7hitTestEPNS_20RenderBoxModelObjectERKNS_14HitTestRequestERNS_13HitTestResultERKNS_15HitTestLocationERKNS_11LayoutPointENS_13HitTestActionE
- fun:_ZN5blink*Render*_14HitTestRequestERNS_13HitTestResultERKNS_15HitTestLocationERKNS_11LayoutPointENS_13HitTestActionE
-}
-{
- bug_417048b
- Memcheck:Uninitialized
- fun:_ZN5blink13InlineFlowBox45clearDescendantsHaveSameLineHeightAndBaselineEv
- ...
- fun:_ZN5blinkL25setLogicalWidthForTextRunEPNS_13RootInlineBoxEPNS_7BidiRunEPNS_10RenderTextEfRKNS*
- fun:_ZN5blink15RenderBlockFlow41computeInlineDirectionPositionsForSegmentEPNS_13RootInlineBoxERKNS*
- fun:_ZN5blink15RenderBlockFlow38computeInlineDirectionPositionsForLineEPNS_13RootInlineBoxERKNS*
-}
-{
- bug_417048c
- Memcheck:Uninitialized
- fun:_ZNK5blink13InlineFlowBox35constrainToLineTopAndBottomIfNeededERNS_10LayoutRectE
- fun:_ZN5blink13InlineFlowBox28paintBoxDecorationBackgroundERNS_9PaintInfoERKNS_11LayoutPointE
- fun:_ZN5blink13InlineFlowBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
- fun:_ZN5blink13InlineFlowBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
- fun:_ZN5blink13RootInlineBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
- fun:_ZNK5blink18LineBoxListPainter5paintEPNS_20RenderBoxModelObjectERNS_9PaintInfoERKNS_11LayoutPointE
-}
-{
- bug_417048d
- Memcheck:Uninitialized
- ...
- fun:_ZNK5blink13RootInlineBox13maxLogicalTopEv
- fun:_ZN5blinkL22computeUnderlineOffsetENS_21TextUnderlinePositionERKNS_11FontMetricsEPKNS_13InlineTextBoxEf
- fun:_ZN5blink13InlineTextBox15paintDecorationEPNS_15GraphicsContextERKNS_10FloatPointENS_14TextDecorationE
- fun:_ZN5blink13InlineTextBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
- fun:_ZN5blink13InlineFlowBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
- fun:_ZN5blink13RootInlineBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
- fun:_ZNK5blink17RenderLineBoxList5paintEPNS_20RenderBoxModelObjectERNS_9PaintInfoERKNS_11LayoutPointE
-}
-{
bug_417119
Memcheck:Leak
fun:_Znw*
@@ -3652,3 +3581,20 @@
fun:_ZN5blink10UseCounterC1Ev
fun:_ZN5blink4PageC1ERNS0_11PageClientsE
}
+{
+ bug_484456
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN7content26GpuProcessTransportFactory23CreatePerCompositorDataEPN2ui10CompositorE
+ fun:_ZN7content26GpuProcessTransportFactory19CreateOutputSurfaceEN4base7WeakPtrIN2ui10CompositorEEE
+ fun:_ZN2ui10Compositor23RequestNewOutputSurfaceEv
+ fun:_ZN2cc13LayerTreeHost23RequestNewOutputSurfaceEv
+ fun:_ZN2cc17SingleThreadProxy23RequestNewOutputSurfaceEv
+}
+{
+ bug_484459
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN7content17ResourceScheduler15OnClientCreatedEiibb
+ fun:_ZN7content26ResourceDispatcherHostImpl23OnRenderViewHostCreatedEiibb
+}
diff --git a/tools/valgrind/memcheck/suppressions_linux.txt b/tools/valgrind/memcheck/suppressions_linux.txt
index 6d031be..cc14d2e 100644
--- a/tools/valgrind/memcheck/suppressions_linux.txt
+++ b/tools/valgrind/memcheck/suppressions_linux.txt
@@ -29,7 +29,7 @@
fun:_ZN7content14RenderViewImpl22OnUpdateWebPreferencesERKNS_14WebPreferencesE
fun:_ZN7content14RenderViewImpl20SetWebkitPreferencesERKNS_14WebPreferencesE
fun:_ZThn*_N7content14RenderViewImpl20SetWebkitPreferencesERKNS_14WebPreferencesE
- fun:_ZN7content16WebKitTestRunner5ResetEv
+ fun:_ZN7content15BlinkTestRunner5ResetEv
}
{
bug_436292
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt
index ac9c687..d887a3f 100644
--- a/tools/valgrind/memcheck/suppressions_mac.txt
+++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -286,5 +286,4 @@
fun:_ZN2v88internal18StackFrameIterator5ResetEPNS0_14ThreadLocalTopE
fun:_ZN2v88internal18StackFrameIteratorC2EPNS0_7IsolateE
fun:_ZN2v88internal18StackFrameIteratorC1EPNS0_7IsolateE
- fun:_ZN2v88internal7Isolate11FindHandlerEv
}