Update from https://crrev.com/312398

Involves adding many //testing/test.gni imports, fixing one
SkSurface::NewRenderTarget invocation inside sky, and fixing up
base::Process usage in the shell.

Review URL: https://codereview.chromium.org/862133002
diff --git a/BUILD.gn b/BUILD.gn
index cb914be..065f871 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/ui.gni")
+import("//testing/test.gni")
 
 if (is_android) {
   import("//build/config/android/rules.gni")
@@ -909,7 +910,10 @@
   # Linux.
   if (is_linux) {
     # TODO(brettw) this will need to be parameterized at some point.
-    linux_configs = [ "//build/config/linux:glib" ]
+    linux_configs = []
+    if (use_glib) {
+      linux_configs += [ "//build/config/linux:glib" ]
+    }
 
     configs += linux_configs
     all_dependent_configs = linux_configs
@@ -1374,6 +1378,13 @@
     "//third_party/icu",
   ]
 
+  if (is_android) {
+    apk_deps = [
+      ":base_java",
+      ":base_java_unittest_support",
+    ]
+  }
+
   if (is_ios) {
     sources -= [
       "metrics/stats_table_uinittest.cc",  # Requires spawning a process.
@@ -1403,10 +1414,12 @@
     sources -= [ "file_version_info_unittest.cc" ]
     sources += [ "nix/xdg_util_unittest.cc" ]
     defines = [ "USE_SYMBOLIZE" ]
-    configs += [ "//build/config/linux:glib" ]
+    if (use_glib) {
+      configs += [ "//build/config/linux:glib" ]
+    }
   }
 
-  if (!is_linux) {
+  if (!is_linux || use_ozone) {
     sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
   }
 
@@ -1526,14 +1539,4 @@
     java_files =
         [ "test/android/java/src/org/chromium/base/ContentUriTestUtils.java" ]
   }
-
-  # GYP: //base.gyp:base_unittests_apk
-  unittest_apk("base_unittests_apk") {
-    deps = [
-      ":base_java",
-      ":base_java_unittest_support",
-      ":base_unittests",
-    ]
-    unittests_dep = ":base_unittests"
-  }
 }
diff --git a/DEPS b/DEPS
index 2407baa..c632e35 100644
--- a/DEPS
+++ b/DEPS
@@ -4,7 +4,6 @@
   "+third_party/apple_apsl",
   "+third_party/libevent",
   "+third_party/dmg_fp",
-  "+third_party/google_toolbox_for_mac/src",
   "+third_party/mach_override",
   "+third_party/modp_b64",
   "+third_party/tcmalloc",
diff --git a/allocator/generic_allocators.cc b/allocator/generic_allocators.cc
index 2726903..ae65f77 100644
--- a/allocator/generic_allocators.cc
+++ b/allocator/generic_allocators.cc
@@ -28,7 +28,7 @@
   return generic_cpp_alloc(size, false);
 }
 
-void operator delete(void* p) {
+void operator delete(void* p) throw() {
   free(p);
 }
 
@@ -36,7 +36,7 @@
   return generic_cpp_alloc(size, false);
 }
 
-void operator delete[](void* p) {
+void operator delete[](void* p) throw() {
   free(p);
 }
 
@@ -44,7 +44,7 @@
   return generic_cpp_alloc(size, true);
 }
 
-void operator delete(void* p, const std::nothrow_t& nt) {
+void operator delete(void* p, const std::nothrow_t& nt) throw() {
   free(p);
 }
 
@@ -52,7 +52,7 @@
   return generic_cpp_alloc(size, true);
 }
 
-void operator delete[](void* p, const std::nothrow_t& nt) {
+void operator delete[](void* p, const std::nothrow_t& nt) throw() {
   free(p);
 }
 
@@ -83,10 +83,6 @@
   return result;
 }
 
-void cfree(void* p) {
-  free(p);
-}
-
 #ifdef WIN32
 
 void* _recalloc(void* p, size_t n, size_t elem_size) {
diff --git a/android/java/src/org/chromium/base/PerfTraceEvent.java b/android/java/src/org/chromium/base/PerfTraceEvent.java
index ca22042..c0e4b21 100644
--- a/android/java/src/org/chromium/base/PerfTraceEvent.java
+++ b/android/java/src/org/chromium/base/PerfTraceEvent.java
@@ -8,6 +8,8 @@
 import android.os.Debug.MemoryInfo;
 import android.util.Log;
 
+import org.chromium.base.annotations.SuppressFBWarnings;
+
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -36,6 +38,7 @@
  * the @TracePerf annotation.  Thus, unlike TraceEvent, we do not
  * support an implicit trace name based on the callstack.
  */
+@SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
 public class PerfTraceEvent {
     private static final int MAX_NAME_LENGTH = 40;
     private static final String MEMORY_TRACE_NAME_SUFFIX = "_BZR_PSS";
diff --git a/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java b/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
new file mode 100644
index 0000000..89068ac
--- /dev/null
+++ b/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
@@ -0,0 +1,20 @@
+// 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.base.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *  @SuppressFBWarnings is used to suppress FindBugs warnings.
+ *
+ *  The long name of FindBugs warnings can be found at
+ *  http://findbugs.sourceforge.net/bugDescriptions.html
+ */
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressFBWarnings {
+    String[] value() default {};
+    String justification() default "";
+}
diff --git a/android/java/src/org/chromium/base/library_loader/Linker.java b/android/java/src/org/chromium/base/library_loader/Linker.java
index d58d1fc..dfcc141 100644
--- a/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -845,6 +845,16 @@
      */
     public static boolean checkMapExecSupport(String apkFile) {
         assert apkFile != null;
+
+        // https://code.google.com/p/chromium/issues/detail?id=448084
+        // Do not check if the device is Samsung Mega.
+        final String model = android.os.Build.MODEL;
+        if (model != null && model.equals("GT-I9205")) {
+            if (DEBUG) Log.i(TAG, "checkMapExecSupport: model is '" + model
+                             + "', returning false");
+            return false;
+        }
+
         synchronized (Linker.class) {
             ensureInitializedLocked();
 
diff --git a/android/java/templates/NativeLibraries.template b/android/java/templates/NativeLibraries.template
index f52acb4..d9f6a55 100644
--- a/android/java/templates/NativeLibraries.template
+++ b/android/java/templates/NativeLibraries.template
@@ -4,6 +4,9 @@
 
 package org.chromium.base.library_loader;
 
+import org.chromium.base.annotations.SuppressFBWarnings;
+
+@SuppressFBWarnings
 public class NativeLibraries {
     /**
      * IMPORTANT NOTE: The variables defined here must _not_ be 'final'.
diff --git a/atomicops.h b/atomicops.h
index 833e170..6a5371c 100644
--- a/atomicops.h
+++ b/atomicops.h
@@ -28,10 +28,14 @@
 #ifndef BASE_ATOMICOPS_H_
 #define BASE_ATOMICOPS_H_
 
-#include <cassert>  // Small C++ header which defines implementation specific
-                    // macros used to identify the STL implementation.
 #include <stdint.h>
 
+// Small C++ header which defines implementation specific macros used to
+// identify the STL implementation.
+// - libc++: captures __config for _LIBCPP_VERSION
+// - libstdc++: captures bits/c++config.h for __GLIBCXX__
+#include <cstddef>
+
 #include "base/base_export.h"
 #include "build/build_config.h"
 
diff --git a/base.gyp b/base.gyp
index 4d5ac00..5d26fc4 100644
--- a/base.gyp
+++ b/base.gyp
@@ -757,6 +757,11 @@
             'message_loop/message_pump_glib_unittest.cc',
           ]
         }],
+        ['use_ozone == 1', {
+          'sources!': [
+            'message_loop/message_pump_glib_unittest.cc',
+          ]
+        }],
         ['OS == "linux" and use_allocator!="none"', {
             'dependencies': [
               'allocator/allocator.gyp:allocator',
diff --git a/base.gypi b/base.gypi
index 14a632d..349308c 100644
--- a/base.gypi
+++ b/base.gypi
@@ -941,6 +941,11 @@
               'strings/string16.cc',
             ],
           },],
+          ['<(use_ozone) == 1', {
+            'sources!': [
+              'message_loop/message_pump_glib.cc',
+            ]
+          }],
           ['OS == "linux" and >(nacl_untrusted_build)==0', {
             'sources!': [
               'files/file_path_watcher_fsevents.cc',
diff --git a/cancelable_callback.h b/cancelable_callback.h
index 91eb046..2b9d260 100644
--- a/cancelable_callback.h
+++ b/cancelable_callback.h
@@ -62,8 +62,7 @@
 
   // |callback| must not be null.
   explicit CancelableCallback(const base::Callback<void(A...)>& callback)
-      : weak_factory_(this),
-        callback_(callback) {
+      : callback_(callback), weak_factory_(this) {
     DCHECK(!callback.is_null());
     InitializeForwarder();
   }
@@ -113,17 +112,15 @@
                             weak_factory_.GetWeakPtr());
   }
 
-  // Used to ensure Forward() is not run when this object is destroyed.
-  // TODO(ckehoe): This should be the last class member.
-  // Move it there when crbug.com/433583 is fixed.
-  base::WeakPtrFactory<CancelableCallback<void(A...)> > weak_factory_;
-
   // The wrapper closure.
   base::Callback<void(A...)> forwarder_;
 
   // The stored closure that may be cancelled.
   base::Callback<void(A...)> callback_;
 
+  // Used to ensure Forward() is not run when this object is destroyed.
+  base::WeakPtrFactory<CancelableCallback<void(A...)>> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
 };
 
diff --git a/files/file_path.h b/files/file_path.h
index 6890866..67bbb4b 100644
--- a/files/file_path.h
+++ b/files/file_path.h
@@ -238,7 +238,7 @@
   // ASSERT(new_path == path.value());
   // NOTE: this is different from the original file_util implementation which
   // returned the extension without a leading "." ("jpg" instead of ".jpg")
-  StringType Extension() const;
+  StringType Extension() const WARN_UNUSED_RESULT;
 
   // Returns the path's file extension, as in Extension(), but will
   // never return a double extension.
@@ -247,7 +247,7 @@
   // we can rename this to Extension() and the other to something like
   // LongExtension(), defaulting to short extensions and leaving the
   // long "extensions" to logic like base::GetUniquePathNumber().
-  StringType FinalExtension() const;
+  StringType FinalExtension() const WARN_UNUSED_RESULT;
 
   // Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
   // NOTE: this is slightly different from the similar file_util implementation
diff --git a/i18n/rtl.cc b/i18n/rtl.cc
index 392cb13..1cccae2 100644
--- a/i18n/rtl.cc
+++ b/i18n/rtl.cc
@@ -74,8 +74,8 @@
 }
 
 // Convert the ICU canonicalized locale to a string.
-std::string GetCanonicalLocale(const char* locale) {
-  return GetLocaleString(icu::Locale::createCanonical(locale));
+std::string GetCanonicalLocale(const std::string& locale) {
+  return GetLocaleString(icu::Locale::createCanonical(locale.c_str()));
 }
 
 // Convert Chrome locale name to ICU locale name
diff --git a/i18n/rtl.h b/i18n/rtl.h
index aa5f681..9b9a0dc 100644
--- a/i18n/rtl.h
+++ b/i18n/rtl.h
@@ -40,7 +40,7 @@
 BASE_I18N_EXPORT std::string GetConfiguredLocale();
 
 // Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name.
-BASE_I18N_EXPORT std::string GetCanonicalLocale(const char* locale);
+BASE_I18N_EXPORT std::string GetCanonicalLocale(const std::string& locale);
 
 // Sets the default locale of ICU.
 // Once the application locale of Chrome in GetApplicationLocale is determined,
diff --git a/ios/weak_nsobject.h b/ios/weak_nsobject.h
index 46aecb5..a1984bb 100644
--- a/ios/weak_nsobject.h
+++ b/ios/weak_nsobject.h
@@ -36,17 +36,28 @@
 // NSObject, this relationship is maintained via the ObjectiveC associated
 // object API, indirectly via an ObjectiveC CRBWeakNSProtocolSentinel class.
 //
-// The implementation assumes that the tracked object will be released on the
-// same thread that the WeakNSObject is created on.
-//
+// Threading restrictions:
+// - Several WeakNSObject pointing to the same underlying object must all be
+//   created and dereferenced on the same thread;
+// - thread safety is enforced by the implementation, except in two cases:
+//   (1) it is allowed to copy a WeakNSObject on a different thread. However,
+//       that copy must return to the original thread before being dereferenced,
+//   (2) it is allowed to destroy a WeakNSObject on any thread;
+// - the implementation assumes that the tracked object will be released on the
+//   same thread that the WeakNSObject is created on.
 namespace base {
 
 // WeakContainer keeps a weak pointer to an object and clears it when it
 // receives nullify() from the object's sentinel.
 class WeakContainer : public base::RefCountedThreadSafe<WeakContainer> {
  public:
-  WeakContainer(id object) : object_(object) {}
-  id object() { return object_; }
+  explicit WeakContainer(id object) : object_(object) {}
+
+  id object() {
+    DCHECK(checker_.CalledOnValidThread());
+    return object_;
+  }
+
   void nullify() {
     DCHECK(checker_.CalledOnValidThread());
     object_ = nil;
@@ -74,53 +85,63 @@
 
 // Base class for all WeakNSObject derivatives.
 template <typename NST>
-class WeakNSProtocol : public base::NonThreadSafe {
+class WeakNSProtocol {
  public:
   explicit WeakNSProtocol(NST object = nil) {
     container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
   }
 
   WeakNSProtocol(const WeakNSProtocol<NST>& that) {
+    // A WeakNSProtocol object can be copied on one thread and used on
+    // another.
+    checker_.DetachFromThread();
     container_ = that.container_;
   }
 
   ~WeakNSProtocol() {
-    // A WeakNSProtocol object can be allocated on one thread and released on
+    // A WeakNSProtocol object can be used on one thread and released on
     // another. This is not the case for the contained object.
-    DetachFromThread();
+    checker_.DetachFromThread();
   }
 
   void reset(NST object = nil) {
-    DCHECK(CalledOnValidThread());
+    DCHECK(checker_.CalledOnValidThread());
     container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
   }
 
   NST get() const {
-    DCHECK(CalledOnValidThread());
+    DCHECK(checker_.CalledOnValidThread());
     if (!container_.get())
       return nil;
     return container_->object();
   }
 
   WeakNSProtocol& operator=(const WeakNSProtocol<NST>& that) {
-    DCHECK(CalledOnValidThread());
+    DCHECK(checker_.CalledOnValidThread());
     container_ = that.container_;
     return *this;
   }
 
   bool operator==(NST that) const {
-    DCHECK(CalledOnValidThread());
+    DCHECK(checker_.CalledOnValidThread());
     return get() == that;
   }
 
-  bool operator!=(NST that) const { return get() != that; }
+  bool operator!=(NST that) const {
+    DCHECK(checker_.CalledOnValidThread());
+    return get() != that;
+  }
 
-  operator NST() const { return get(); }
+  operator NST() const {
+    DCHECK(checker_.CalledOnValidThread());
+    return get();
+  }
 
  private:
   // Refecounted reference to the container tracking the ObjectiveC object this
   // class encapsulates.
   scoped_refptr<base::WeakContainer> container_;
+  base::ThreadChecker checker_;
 };
 
 // Free functions
diff --git a/ios/weak_nsobject_unittest.mm b/ios/weak_nsobject_unittest.mm
index 9758aed..325dcd2 100644
--- a/ios/weak_nsobject_unittest.mm
+++ b/ios/weak_nsobject_unittest.mm
@@ -3,16 +3,19 @@
 // found in the LICENSE file.
 
 #include "base/basictypes.h"
+#include "base/bind.h"
 #include "base/ios/weak_nsobject.h"
 #include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::WeakNSObject;
-
+namespace base {
 namespace {
 
 TEST(WeakNSObjectTest, WeakNSObject) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
   WeakNSObject<NSObject> w1(p1);
   EXPECT_TRUE(w1);
   p1.reset();
@@ -20,7 +23,7 @@
 }
 
 TEST(WeakNSObjectTest, MultipleWeakNSObject) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
   WeakNSObject<NSObject> w1(p1);
   WeakNSObject<NSObject> w2(w1);
   EXPECT_TRUE(w1);
@@ -32,7 +35,7 @@
 }
 
 TEST(WeakNSObjectTest, WeakNSObjectDies) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
   {
     WeakNSObject<NSObject> w1(p1);
     EXPECT_TRUE(w1);
@@ -40,7 +43,7 @@
 }
 
 TEST(WeakNSObjectTest, WeakNSObjectReset) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
   WeakNSObject<NSObject> w1(p1);
   EXPECT_TRUE(w1);
   w1.reset();
@@ -50,8 +53,8 @@
 }
 
 TEST(WeakNSObjectTest, WeakNSObjectResetWithObject) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
-  base::scoped_nsobject<NSObject> p2([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p2([[NSObject alloc] init]);
   WeakNSObject<NSObject> w1(p1);
   EXPECT_TRUE(w1);
   w1.reset(p2);
@@ -61,7 +64,7 @@
 }
 
 TEST(WeakNSObjectTest, WeakNSObjectEmpty) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
   WeakNSObject<NSObject> w1;
   EXPECT_FALSE(w1);
   w1.reset(p1);
@@ -71,7 +74,7 @@
 }
 
 TEST(WeakNSObjectTest, WeakNSObjectCopy) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
   WeakNSObject<NSObject> w1(p1);
   WeakNSObject<NSObject> w2(w1);
   EXPECT_TRUE(w1);
@@ -82,7 +85,7 @@
 }
 
 TEST(WeakNSObjectTest, WeakNSObjectAssignment) {
-  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
   WeakNSObject<NSObject> w1(p1);
   WeakNSObject<NSObject> w2;
   EXPECT_FALSE(w2);
@@ -94,4 +97,40 @@
   EXPECT_FALSE(w2);
 }
 
+// Touches |weak_data| by increasing its length by 1. Used to check that the
+// weak object can be dereferenced.
+void TouchWeakData(const WeakNSObject<NSMutableData>& weak_data) {
+  if (!weak_data)
+    return;
+  [weak_data increaseLengthBy:1];
+}
+
+// Makes a copy of |weak_object| on the current thread and posts a task to touch
+// the weak object on its original thread.
+void CopyWeakNSObjectAndPost(const WeakNSObject<NSMutableData>& weak_object,
+                             scoped_refptr<SingleThreadTaskRunner> runner) {
+  WeakNSObject<NSMutableData> weak_copy(weak_object);
+  runner->PostTask(FROM_HERE, Bind(&TouchWeakData, weak_copy));
+}
+
+// Tests that the weak object can be copied on a different thread.
+TEST(WeakNSObjectTest, WeakNSObjectCopyOnOtherThread) {
+  MessageLoop loop;
+  Thread other_thread("WeakNSObjectCopyOnOtherThread");
+  other_thread.Start();
+
+  scoped_nsobject<NSMutableData> data([[NSMutableData alloc] init]);
+  WeakNSObject<NSMutableData> weak(data);
+
+  scoped_refptr<SingleThreadTaskRunner> runner = loop.task_runner();
+  other_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&CopyWeakNSObjectAndPost, weak, runner));
+  other_thread.Stop();
+  loop.RunUntilIdle();
+
+  // Check that TouchWeakData was called.
+  EXPECT_EQ(1u, [data length]);
+}
+
 }  // namespace
+}  // namespace base
diff --git a/mac/cocoa_protocols.h b/mac/cocoa_protocols.h
index e10001f..ab34a19 100644
--- a/mac/cocoa_protocols.h
+++ b/mac/cocoa_protocols.h
@@ -7,10 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-// GTM also maintains a list of empty protocols, but only the ones the library
-// requires. Augment that below.
-#import "third_party/google_toolbox_for_mac/src/GTMDefines.h"
-
 // New Mac OS X SDKs introduce new protocols used for delegates.  These
 // protocol defintions aren't not present in earlier releases of the Mac OS X
 // SDK.  In order to support building against the new SDK, which requires
diff --git a/mac/scoped_nsobject.h b/mac/scoped_nsobject.h
index 8d7bd4a..8814b51 100644
--- a/mac/scoped_nsobject.h
+++ b/mac/scoped_nsobject.h
@@ -40,6 +40,11 @@
       : object_([that.object_ retain]) {
   }
 
+  template <typename NSU>
+  scoped_nsprotocol(const scoped_nsprotocol<NSU>& that)
+      : object_([that.get() retain]) {
+  }
+
   ~scoped_nsprotocol() {
     [object_ release];
   }
@@ -119,6 +124,11 @@
       : scoped_nsprotocol<NST*>(that) {
   }
 
+  template<typename NSU>
+  scoped_nsobject(const scoped_nsobject<NSU>& that)
+      : scoped_nsprotocol<NST*>(that) {
+  }
+
   scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
     scoped_nsprotocol<NST*>::operator=(that);
     return *this;
@@ -135,6 +145,11 @@
       : scoped_nsprotocol<id>(that) {
   }
 
+  template<typename NSU>
+  scoped_nsobject(const scoped_nsobject<NSU>& that)
+      : scoped_nsprotocol<id>(that) {
+  }
+
   scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
     scoped_nsprotocol<id>::operator=(that);
     return *this;
diff --git a/mac/sdk_forward_declarations.h b/mac/sdk_forward_declarations.h
index f606dab..faa36ea 100644
--- a/mac/sdk_forward_declarations.h
+++ b/mac/sdk_forward_declarations.h
@@ -105,6 +105,7 @@
 - (void)setAnimationBehavior:(NSWindowAnimationBehavior)newAnimationBehavior;
 - (void)toggleFullScreen:(id)sender;
 - (void)setRestorable:(BOOL)flag;
+- (NSRect)convertRectFromScreen:(NSRect)aRect;
 @end
 
 @interface NSCursor (LionSDKDeclarations)
diff --git a/memory/scoped_vector.h b/memory/scoped_vector.h
index 1b30f63..173ea5a 100644
--- a/memory/scoped_vector.h
+++ b/memory/scoped_vector.h
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/move.h"
 #include "base/stl_util.h"
 
@@ -64,6 +65,7 @@
   reference back() { return v_.back(); }
 
   void push_back(T* elem) { v_.push_back(elem); }
+  void push_back(scoped_ptr<T> elem) { v_.push_back(elem.release()); }
 
   void pop_back() {
     DCHECK(!empty());
diff --git a/memory/scoped_vector_unittest.cc b/memory/scoped_vector_unittest.cc
index b60ca14..220cfb0 100644
--- a/memory/scoped_vector_unittest.cc
+++ b/memory/scoped_vector_unittest.cc
@@ -308,4 +308,17 @@
     EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
 }
 
+// Assertions for push_back(scoped_ptr).
+TEST(ScopedVectorTest, PushBackScopedPtr) {
+  int delete_counter = 0;
+  scoped_ptr<DeleteCounter> elem(new DeleteCounter(&delete_counter));
+  EXPECT_EQ(0, delete_counter);
+  {
+    ScopedVector<DeleteCounter> v;
+    v.push_back(elem.Pass());
+    EXPECT_EQ(0, delete_counter);
+  }
+  EXPECT_EQ(1, delete_counter);
+}
+
 }  // namespace
diff --git a/message_loop/message_pump_io_ios.h b/message_loop/message_pump_io_ios.h
index 18af4a8..317a59c 100644
--- a/message_loop/message_pump_io_ios.h
+++ b/message_loop/message_pump_io_ios.h
@@ -97,7 +97,7 @@
   };
 
   MessagePumpIOSForIO();
-  virtual ~MessagePumpIOSForIO();
+  ~MessagePumpIOSForIO() override;
 
   // Have the current thread's message loop watch for a a situation in which
   // reading/writing to the FD can be performed without blocking.
diff --git a/message_loop/message_pump_io_ios_unittest.cc b/message_loop/message_pump_io_ios_unittest.cc
index 0bf8c08..ba96f83 100644
--- a/message_loop/message_pump_io_ios_unittest.cc
+++ b/message_loop/message_pump_io_ios_unittest.cc
@@ -18,9 +18,9 @@
   MessagePumpIOSForIOTest()
       : ui_loop_(MessageLoop::TYPE_UI),
         io_thread_("MessagePumpIOSForIOTestIOThread") {}
-  virtual ~MessagePumpIOSForIOTest() {}
+  ~MessagePumpIOSForIOTest() override {}
 
-  virtual void SetUp() override {
+  void SetUp() override {
     Thread::Options options(MessageLoop::TYPE_IO, 0);
     ASSERT_TRUE(io_thread_.StartWithOptions(options));
     ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
@@ -30,7 +30,7 @@
     ASSERT_EQ(0, ret);
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     if (IGNORE_EINTR(close(pipefds_[0])) < 0)
       PLOG(ERROR) << "close";
     if (IGNORE_EINTR(close(pipefds_[1])) < 0)
@@ -64,11 +64,11 @@
 // nothing useful.
 class StupidWatcher : public MessagePumpIOSForIO::Watcher {
  public:
-  virtual ~StupidWatcher() {}
+  ~StupidWatcher() override {}
 
   // base:MessagePumpIOSForIO::Watcher interface
-  virtual void OnFileCanReadWithoutBlocking(int fd) override {}
-  virtual void OnFileCanWriteWithoutBlocking(int fd) override {}
+  void OnFileCanReadWithoutBlocking(int fd) override {}
+  void OnFileCanWriteWithoutBlocking(int fd) override {}
 };
 
 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
@@ -93,16 +93,12 @@
       : controller_(controller) {
     DCHECK(controller_);
   }
-  virtual ~BaseWatcher() {}
+  ~BaseWatcher() override {}
 
   // MessagePumpIOSForIO::Watcher interface
-  virtual void OnFileCanReadWithoutBlocking(int /* fd */) override {
-    NOTREACHED();
-  }
+  void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
 
-  virtual void OnFileCanWriteWithoutBlocking(int /* fd */) override {
-    NOTREACHED();
-  }
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
 
  protected:
   MessagePumpIOSForIO::FileDescriptorWatcher* controller_;
@@ -114,11 +110,9 @@
       MessagePumpIOSForIO::FileDescriptorWatcher* controller)
       : BaseWatcher(controller) {}
 
-  virtual ~DeleteWatcher() {
-    DCHECK(!controller_);
-  }
+  ~DeleteWatcher() override { DCHECK(!controller_); }
 
-  virtual void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
     DCHECK(controller_);
     delete controller_;
     controller_ = NULL;
@@ -146,9 +140,9 @@
         pump_(pump),
         fd_to_start_watching_(fd_to_start_watching) {}
 
-  virtual ~StopWatcher() {}
+  ~StopWatcher() override {}
 
-  virtual void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
     controller_->StopWatchingFileDescriptor();
     if (fd_to_start_watching_ >= 0) {
       pump_->WatchFileDescriptor(fd_to_start_watching_,
diff --git a/message_loop/message_pump_mac.h b/message_loop/message_pump_mac.h
index 55ab2c6..c853202 100644
--- a/message_loop/message_pump_mac.h
+++ b/message_loop/message_pump_mac.h
@@ -263,9 +263,9 @@
 class MessagePumpUIApplication : public MessagePumpCFRunLoopBase {
  public:
   MessagePumpUIApplication();
-  virtual ~MessagePumpUIApplication();
-  virtual void DoRun(Delegate* delegate) override;
-  virtual void Quit() override;
+  ~MessagePumpUIApplication() override;
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
 
   // This message pump can not spin the main message loop directly.  Instead,
   // call |Attach()| to set up a delegate.  It is an error to call |Run()|.
diff --git a/message_loop/message_pump_win.cc b/message_loop/message_pump_win.cc
index c140691..a7a1485 100644
--- a/message_loop/message_pump_win.cc
+++ b/message_loop/message_pump_win.cc
@@ -162,6 +162,11 @@
 // static
 LRESULT CALLBACK MessagePumpForUI::WndProcThunk(
     HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::WndProcThunk"));
+
   switch (message) {
     case kMsgHaveWork:
       reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
diff --git a/metrics/field_trial.cc b/metrics/field_trial.cc
index 7efca7a..e03c94c 100644
--- a/metrics/field_trial.cc
+++ b/metrics/field_trial.cc
@@ -223,6 +223,20 @@
   return true;
 }
 
+bool FieldTrial::GetState(FieldTrialState* field_trial_state) const {
+  if (!enable_field_trial_)
+    return false;
+  field_trial_state->trial_name = trial_name_;
+  // If the group name is empty (hasn't been finalized yet), use the default
+  // group name instead.
+  if (!group_name_.empty())
+    field_trial_state->group_name = group_name_;
+  else
+    field_trial_state->group_name = default_group_name_;
+  field_trial_state->activated = group_reported_;
+  return true;
+}
+
 //------------------------------------------------------------------------------
 // FieldTrialList methods and members.
 
@@ -387,6 +401,29 @@
 }
 
 // static
+void FieldTrialList::AllStatesToString(std::string* output) {
+  if (!global_)
+    return;
+  AutoLock auto_lock(global_->lock_);
+
+  for (const auto& registered : global_->registered_) {
+    FieldTrial::FieldTrialState trial;
+    if (!registered.second->GetState(&trial))
+      continue;
+    DCHECK_EQ(std::string::npos,
+              trial.trial_name.find(kPersistentStringSeparator));
+    DCHECK_EQ(std::string::npos,
+              trial.group_name.find(kPersistentStringSeparator));
+    if (trial.activated)
+      output->append(1, kActivationMarker);
+    output->append(trial.trial_name);
+    output->append(1, kPersistentStringSeparator);
+    output->append(trial.group_name);
+    output->append(1, kPersistentStringSeparator);
+  }
+}
+
+// static
 void FieldTrialList::GetActiveFieldTrialGroups(
     FieldTrial::ActiveGroups* active_groups) {
   DCHECK(active_groups->empty());
diff --git a/metrics/field_trial.h b/metrics/field_trial.h
index e2e5439..26257ab 100644
--- a/metrics/field_trial.h
+++ b/metrics/field_trial.h
@@ -106,6 +106,14 @@
     std::string group_name;
   };
 
+  // A triplet representing a FieldTrial, its selected group and whether it's
+  // active.
+  struct FieldTrialState {
+    std::string trial_name;
+    std::string group_name;
+    bool activated;
+  };
+
   typedef std::vector<ActiveGroup> ActiveGroups;
 
   // A return value to indicate that a given instance has not yet had a group
@@ -180,8 +188,10 @@
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AllGroups);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SaveAll);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn);
@@ -230,6 +240,13 @@
   // untouched.
   bool GetActiveGroup(ActiveGroup* active_group) const;
 
+  // Returns the trial name and selected group name for this field trial via
+  // the output parameter |field_trial_state|, but only if the trial has not
+  // been disabled. In that case, true is returned and |field_trial_state| is
+  // filled in; otherwise, the result is false and |field_trial_state| is left
+  // untouched.
+  bool GetState(FieldTrialState* field_trial_state) const;
+
   // Returns the group_name. A winner need not have been chosen.
   std::string group_name_internal() const { return group_name_; }
 
@@ -404,6 +421,16 @@
   // by |CreateTrialsFromString()|.
   static void StatesToString(std::string* output);
 
+  // Creates a persistent representation of all FieldTrial instances for
+  // resurrection in another process. This allows randomization to be done in
+  // one process, and secondary processes can be synchronized on the result.
+  // The resulting string contains the name and group name pairs of all
+  // registered FieldTrials which have not been disabled, with "/" used
+  // to separate all names and to terminate the string. All activated trials
+  // have their name prefixed with "*". This string is parsed by
+  // |CreateTrialsFromString()|.
+  static void AllStatesToString(std::string* output);
+
   // Fills in the supplied vector |active_groups| (which must be empty when
   // called) with a snapshot of all registered FieldTrials for which the group
   // has been chosen and externally observed (via |group()|) and which have
diff --git a/metrics/field_trial_unittest.cc b/metrics/field_trial_unittest.cc
index ce95c2a..f1a1042 100644
--- a/metrics/field_trial_unittest.cc
+++ b/metrics/field_trial_unittest.cc
@@ -311,6 +311,36 @@
   }
 }
 
+TEST_F(FieldTrialTest, AllGroups) {
+  FieldTrial::FieldTrialState field_trial_state;
+  std::string one_winner("One Winner");
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(one_winner, 10, "Default", NULL);
+  std::string winner("Winner");
+  trial->AppendGroup(winner, 10);
+  EXPECT_TRUE(trial->GetState(&field_trial_state));
+  EXPECT_EQ(one_winner, field_trial_state.trial_name);
+  EXPECT_EQ(winner, field_trial_state.group_name);
+  trial->group();
+  EXPECT_TRUE(trial->GetState(&field_trial_state));
+  EXPECT_EQ(one_winner, field_trial_state.trial_name);
+  EXPECT_EQ(winner, field_trial_state.group_name);
+
+  std::string multi_group("MultiGroup");
+  scoped_refptr<FieldTrial> multi_group_trial =
+      CreateFieldTrial(multi_group, 9, "Default", NULL);
+
+  multi_group_trial->AppendGroup("Me", 3);
+  multi_group_trial->AppendGroup("You", 3);
+  multi_group_trial->AppendGroup("Them", 3);
+  EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
+  // Finalize the group selection by accessing the selected group.
+  multi_group_trial->group();
+  EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
+  EXPECT_EQ(multi_group, field_trial_state.trial_name);
+  EXPECT_EQ(multi_group_trial->group_name(), field_trial_state.group_name);
+}
+
 TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
   const char kTrialName[] = "TestTrial";
   const char kSecondaryGroupName[] = "SecondaryGroup";
@@ -388,6 +418,44 @@
   EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string);
 }
 
+TEST_F(FieldTrialTest, SaveAll) {
+  std::string save_string;
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some name", 10, "Default some name", NULL);
+  EXPECT_EQ("", trial->group_name_internal());
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("Some name/Default some name/", save_string);
+  save_string.clear();
+
+  // Create a winning group.
+  trial->AppendGroup("Winner", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("*Some name/Winner/", save_string);
+  save_string.clear();
+
+  // Create a second trial and winning group.
+  scoped_refptr<FieldTrial> trial2 =
+      CreateFieldTrial("xxx", 10, "Default xxx", NULL);
+  trial2->AppendGroup("yyyy", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial2->group();
+
+  FieldTrialList::AllStatesToString(&save_string);
+  // We assume names are alphabetized... though this is not critical.
+  EXPECT_EQ("*Some name/Winner/*xxx/yyyy/", save_string);
+  save_string.clear();
+
+  // Create a third trial with only the default group.
+  scoped_refptr<FieldTrial> trial3 =
+      CreateFieldTrial("zzz", 10, "default", NULL);
+
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("*Some name/Winner/*xxx/yyyy/zzz/default/", save_string);
+}
+
 TEST_F(FieldTrialTest, Restore) {
   ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
   ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
@@ -1014,6 +1082,43 @@
   }
 }
 
+TEST(FieldTrialTestWithoutList, StatesStringFormat) {
+  std::string save_string;
+
+  // Scoping the first FieldTrialList, as we need another one to test the
+  // importing function.
+  {
+    FieldTrialList field_trial_list(NULL);
+    scoped_refptr<FieldTrial> trial =
+        CreateFieldTrial("Abc", 10, "Default some name", NULL);
+    trial->AppendGroup("cba", 10);
+    trial->group();
+    scoped_refptr<FieldTrial> trial2 =
+        CreateFieldTrial("Xyz", 10, "Default xxx", NULL);
+    trial2->AppendGroup("zyx", 10);
+    trial2->group();
+    scoped_refptr<FieldTrial> trial3 =
+        CreateFieldTrial("zzz", 10, "default", NULL);
+
+    FieldTrialList::AllStatesToString(&save_string);
+  }
+
+  // Starting with a new blank FieldTrialList.
+  FieldTrialList field_trial_list(NULL);
+  ASSERT_TRUE(field_trial_list.CreateTrialsFromString(
+      save_string, FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  field_trial_list.GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("Abc", active_groups[0].trial_name);
+  EXPECT_EQ("cba", active_groups[0].group_name);
+  EXPECT_EQ("Xyz", active_groups[1].trial_name);
+  EXPECT_EQ("zyx", active_groups[1].group_name);
+  EXPECT_TRUE(field_trial_list.TrialExists("zzz"));
+}
+
 #if GTEST_HAS_DEATH_TEST
 TEST(FieldTrialDeathTest, OneTimeRandomizedTrialWithoutFieldTrialList) {
   // Trying to instantiate a one-time randomized field trial before the
diff --git a/power_monitor/power_monitor_device_source_win.cc b/power_monitor/power_monitor_device_source_win.cc
index b8b16e1..0e199dc 100644
--- a/power_monitor/power_monitor_device_source_win.cc
+++ b/power_monitor/power_monitor_device_source_win.cc
@@ -5,6 +5,7 @@
 #include "base/power_monitor/power_monitor.h"
 #include "base/power_monitor/power_monitor_device_source.h"
 #include "base/power_monitor/power_monitor_source.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/win/wrapped_window_proc.h"
 
 namespace base {
@@ -98,6 +99,11 @@
     UINT message,
     WPARAM wparam,
     LPARAM lparam) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk"));
+
   switch (message) {
     case WM_POWERBROADCAST:
       ProcessWmPowerBroadcastMessage(wparam);
diff --git a/process/kill.h b/process/kill.h
index f697701..e8ce334 100644
--- a/process/kill.h
+++ b/process/kill.h
@@ -154,8 +154,8 @@
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 // The nicer version of EnsureProcessTerminated() that is patient and will
-// wait for |process_handle| to finish and then reap it.
-BASE_EXPORT void EnsureProcessGetsReaped(ProcessHandle process_handle);
+// wait for |pid| to finish and then reap it.
+BASE_EXPORT void EnsureProcessGetsReaped(ProcessId pid);
 #endif
 
 }  // namespace base
diff --git a/process/kill_posix.cc b/process/kill_posix.cc
index 3f304ca..9e9b5fb 100644
--- a/process/kill_posix.cc
+++ b/process/kill_posix.cc
@@ -473,12 +473,12 @@
   PlatformThread::CreateNonJoinable(0, reaper);
 }
 
-void EnsureProcessGetsReaped(ProcessHandle process) {
+void EnsureProcessGetsReaped(ProcessId pid) {
   // If the child is already dead, then there's nothing to do.
-  if (IsChildDead(process))
+  if (IsChildDead(pid))
     return;
 
-  BackgroundReaper* reaper = new BackgroundReaper(process, 0);
+  BackgroundReaper* reaper = new BackgroundReaper(pid, 0);
   PlatformThread::CreateNonJoinable(0, reaper);
 }
 
diff --git a/process/launch.cc b/process/launch.cc
index a1c4d21..1c752bd 100644
--- a/process/launch.cc
+++ b/process/launch.cc
@@ -28,6 +28,9 @@
       , clone_flags(0)
       , allow_new_privs(false)
 #endif  // OS_LINUX
+#if defined(OS_POSIX)
+      , pre_exec_delegate(NULL)
+#endif  // OS_POSIX
 #if defined(OS_CHROMEOS)
       , ctrl_terminal_fd(-1)
 #endif  // OS_CHROMEOS
diff --git a/process/launch.h b/process/launch.h
index 6cd02d6..eca4f8f 100644
--- a/process/launch.h
+++ b/process/launch.h
@@ -37,6 +37,24 @@
 // Options for launching a subprocess that are passed to LaunchProcess().
 // The default constructor constructs the object with default options.
 struct BASE_EXPORT LaunchOptions {
+#if defined(OS_POSIX)
+  // Delegate to be run in between fork and exec in the subprocess (see
+  // pre_exec_delegate below)
+  class BASE_EXPORT PreExecDelegate {
+   public:
+    PreExecDelegate() {}
+    virtual ~PreExecDelegate() {}
+
+    // Since this is to be run between fork and exec, and fork may have happened
+    // while multiple threads were running, this function needs to be async
+    // safe.
+    virtual void RunAsyncSafe() = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PreExecDelegate);
+  };
+#endif  // defined(OS_POSIX)
+
   LaunchOptions();
   ~LaunchOptions();
 
@@ -115,6 +133,9 @@
 
 #if defined(OS_LINUX)
   // If non-zero, start the process using clone(), using flags as provided.
+  // Unlike in clone, clone_flags may not contain a custom termination signal
+  // that is sent to the parent when the child dies. The termination signal will
+  // always be set to SIGCHLD.
   int clone_flags;
 
   // By default, child processes will have the PR_SET_NO_NEW_PRIVS bit set. If
@@ -122,6 +143,16 @@
   bool allow_new_privs;
 #endif  // defined(OS_LINUX)
 
+#if defined(OS_POSIX)
+  // If non-null, a delegate to be run immediately prior to executing the new
+  // program in the child process.
+  //
+  // WARNING: If LaunchProcess is called in the presence of multiple threads,
+  // code running in this delegate essentially needs to be async-signal safe
+  // (see man 7 signal for a list of allowed functions).
+  PreExecDelegate* pre_exec_delegate;
+#endif  // defined(OS_POSIX)
+
 #if defined(OS_CHROMEOS)
   // If non-negative, the specified file descriptor will be set as the launched
   // process' controlling terminal.
@@ -156,12 +187,6 @@
 BASE_EXPORT Process LaunchProcess(const CommandLine& cmdline,
                                   const LaunchOptions& options);
 
-// Deprecated version.
-// TODO(rvargas) crbug.com/417532: Remove this after migrating all consumers.
-BASE_EXPORT bool LaunchProcess(const CommandLine& cmdline,
-                               const LaunchOptions& options,
-                               ProcessHandle* process_handle);
-
 #if defined(OS_WIN)
 // Windows-specific LaunchProcess that takes the command line as a
 // string.  Useful for situations where you need to control the
@@ -192,12 +217,6 @@
 BASE_EXPORT Process LaunchProcess(const std::vector<std::string>& argv,
                                   const LaunchOptions& options);
 
-// Deprecated version.
-// TODO(rvargas) crbug.com/417532: Remove this after migrating all consumers.
-BASE_EXPORT bool LaunchProcess(const std::vector<std::string>& argv,
-                               const LaunchOptions& options,
-                               ProcessHandle* process_handle);
-
 // Close all file descriptors, except those which are a destination in the
 // given multimap. Only call this function in a child process where you know
 // that there aren't any other threads.
diff --git a/process/launch_posix.cc b/process/launch_posix.cc
index c60cfdc..6c9ed3f 100644
--- a/process/launch_posix.cc
+++ b/process/launch_posix.cc
@@ -277,9 +277,13 @@
   }
 }
 
-bool LaunchProcess(const std::vector<std::string>& argv,
-                   const LaunchOptions& options,
-                   ProcessHandle* process_handle) {
+Process LaunchProcess(const CommandLine& cmdline,
+                      const LaunchOptions& options) {
+  return LaunchProcess(cmdline.argv(), options);
+}
+
+Process LaunchProcess(const std::vector<std::string>& argv,
+                      const LaunchOptions& options) {
   size_t fd_shuffle_size = 0;
   if (options.fds_to_remap) {
     fd_shuffle_size = options.fds_to_remap->size();
@@ -311,7 +315,17 @@
     // and that signal handling follows the process-creation rules.
     RAW_CHECK(
         !(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM)));
-    pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0);
+
+    // We specify a null ptid and ctid.
+    RAW_CHECK(
+        !(options.clone_flags &
+          (CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT_SETTID)));
+
+    // Since we use waitpid, we do not support custom termination signals in the
+    // clone flags.
+    RAW_CHECK((options.clone_flags & 0xff) == 0);
+
+    pid = ForkWithFlags(options.clone_flags | SIGCHLD, nullptr, nullptr);
   } else
 #endif
   {
@@ -325,7 +339,7 @@
 
   if (pid < 0) {
     DPLOG(ERROR) << "fork";
-    return false;
+    return Process();
   } else if (pid == 0) {
     // Child process
 
@@ -448,6 +462,12 @@
     }
 #endif
 
+#if defined(OS_POSIX)
+    if (options.pre_exec_delegate != nullptr) {
+      options.pre_exec_delegate->RunAsyncSafe();
+    }
+#endif
+
     for (size_t i = 0; i < argv.size(); i++)
       argv_cstr[i] = const_cast<char*>(argv[i].c_str());
     argv_cstr[argv.size()] = NULL;
@@ -465,37 +485,9 @@
       pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
       DPCHECK(ret > 0);
     }
-
-    if (process_handle)
-      *process_handle = pid;
   }
 
-  return true;
-}
-
-Process LaunchProcess(const std::vector<std::string>& argv,
-                      const LaunchOptions& options) {
-  ProcessHandle process_handle;
-  if (LaunchProcess(argv, options, &process_handle))
-    return Process(process_handle);
-
-  return Process();
-}
-
-
-bool LaunchProcess(const CommandLine& cmdline,
-                   const LaunchOptions& options,
-                   ProcessHandle* process_handle) {
-  return LaunchProcess(cmdline.argv(), options, process_handle);
-}
-
-Process LaunchProcess(const CommandLine& cmdline,
-                      const LaunchOptions& options) {
-  ProcessHandle process_handle;
-  if (LaunchProcess(cmdline, options, &process_handle))
-    return Process(process_handle);
-
-  return Process();
+  return Process(pid);
 }
 
 void RaiseProcessToHighPriority() {
diff --git a/process/launch_win.cc b/process/launch_win.cc
index 1d83ef9..c2bd295 100644
--- a/process/launch_win.cc
+++ b/process/launch_win.cc
@@ -105,9 +105,13 @@
   std::ios::sync_with_stdio();
 }
 
-bool LaunchProcess(const string16& cmdline,
-                   const LaunchOptions& options,
-                   win::ScopedHandle* process_handle) {
+Process LaunchProcess(const CommandLine& cmdline,
+                      const LaunchOptions& options) {
+  return LaunchProcess(cmdline.GetCommandLineString(), options);
+}
+
+Process LaunchProcess(const string16& cmdline,
+                      const LaunchOptions& options) {
   win::StartupInformation startup_info_wrapper;
   STARTUPINFO* startup_info = startup_info_wrapper.startup_info();
 
@@ -119,18 +123,18 @@
     } else {
       if (base::win::GetVersion() < base::win::VERSION_VISTA) {
         DLOG(ERROR) << "Specifying handles to inherit requires Vista or later.";
-        return false;
+        return Process();
       }
 
       if (options.handles_to_inherit->size() >
               std::numeric_limits<DWORD>::max() / sizeof(HANDLE)) {
         DLOG(ERROR) << "Too many handles to inherit.";
-        return false;
+        return Process();
       }
 
       if (!startup_info_wrapper.InitializeProcThreadAttributeList(1)) {
         DPLOG(ERROR);
-        return false;
+        return Process();
       }
 
       if (!startup_info_wrapper.UpdateProcThreadAttribute(
@@ -139,7 +143,7 @@
               static_cast<DWORD>(options.handles_to_inherit->size() *
                   sizeof(HANDLE)))) {
         DPLOG(ERROR);
-        return false;
+        return Process();
       }
 
       inherit_handles = true;
@@ -184,7 +188,7 @@
 
     if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) {
       DPLOG(ERROR);
-      return false;
+      return Process();
     }
 
     BOOL launched =
@@ -197,7 +201,7 @@
     if (!launched) {
       DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
                    << std::endl;;
-      return false;
+      return Process();
     }
   } else {
     if (!CreateProcess(NULL,
@@ -206,7 +210,7 @@
                        startup_info, &temp_process_info)) {
       DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
                    << std::endl;;
-      return false;
+      return Process();
     }
   }
   base::win::ScopedProcessInformation process_info(temp_process_info);
@@ -216,7 +220,7 @@
                                       process_info.process_handle())) {
       DLOG(ERROR) << "Could not AssignProcessToObject.";
       KillProcess(process_info.process_handle(), kProcessKilledExitCode, true);
-      return false;
+      return Process();
     }
 
     ResumeThread(process_info.thread_handle());
@@ -225,43 +229,7 @@
   if (options.wait)
     WaitForSingleObject(process_info.process_handle(), INFINITE);
 
-  // If the caller wants the process handle, we won't close it.
-  if (process_handle)
-    process_handle->Set(process_info.TakeProcessHandle());
-
-  return true;
-}
-
-// TODO(rvargas) crbug.com/416721: Remove this stub after LaunchProcess is
-// fully migrated to use Process.
-Process LaunchProcess(const string16& cmdline,
-                      const LaunchOptions& options) {
-  win::ScopedHandle process_handle;
-  if (LaunchProcess(cmdline, options, &process_handle))
-    return Process(process_handle.Take());
-
-  return Process();
-}
-
-bool LaunchProcess(const CommandLine& cmdline,
-                   const LaunchOptions& options,
-                   ProcessHandle* process_handle) {
-  if (!process_handle)
-    return LaunchProcess(cmdline.GetCommandLineString(), options, NULL);
-
-  win::ScopedHandle process;
-  bool rv = LaunchProcess(cmdline.GetCommandLineString(), options, &process);
-  *process_handle = process.Take();
-  return rv;
-}
-
-Process LaunchProcess(const CommandLine& cmdline,
-                      const LaunchOptions& options) {
-  ProcessHandle process_handle;
-  if (LaunchProcess(cmdline, options, &process_handle))
-    return Process(process_handle);
-
-  return Process();
+  return Process(process_info.TakeProcessHandle());
 }
 
 Process LaunchElevatedProcess(const CommandLine& cmdline,
diff --git a/process/process.h b/process/process.h
index ad8f8ee..b0fd8d9 100644
--- a/process/process.h
+++ b/process/process.h
@@ -49,6 +49,11 @@
   // Returns an object for the current process.
   static Process Current();
 
+  // Returns a Process for the given |pid|. On Windows the handle is opened
+  // with more access rights and must only be used by trusted code (can read the
+  // address space and duplicate handles).
+  static Process OpenWithExtraPriviles(ProcessId pid);
+
   // Creates an object from a |handle| owned by someone else.
   // Don't use this for new code. It is only intended to ease the migration to
   // a strict ownership model.
@@ -112,6 +117,25 @@
 #endif
 };
 
+#if defined(OS_LINUX)
+// A wrapper for clone with fork-like behavior, meaning that it returns the
+// child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are
+// as in the clone system call (the CLONE_VM flag is not supported).
+//
+// This function uses the libc clone wrapper (which updates libc's pid cache)
+// internally, so callers may expect things like getpid() to work correctly
+// after in both the child and parent. An exception is when this code is run
+// under Valgrind. Valgrind does not support the libc clone wrapper, so the libc
+// pid cache may be incorrect after this function is called under Valgrind.
+//
+// As with fork(), callers should be extremely careful when calling this while
+// multiple threads are running, since at the time the fork happened, the
+// threads could have been in any state (potentially holding locks, etc.).
+// Callers should most likely call execve() in the child soon after calling
+// this.
+BASE_EXPORT pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid);
+#endif
+
 }  // namespace base
 
 #endif  // BASE_PROCESS_PROCESS_PROCESS_H_
diff --git a/process/process_handle.h b/process/process_handle.h
index 6f8094e..368f952 100644
--- a/process/process_handle.h
+++ b/process/process_handle.h
@@ -44,15 +44,6 @@
 // CloseProcessHandle when you are done with it. Returns true on success.
 BASE_EXPORT bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
 
-// Converts a PID to a process handle. On Windows the handle is opened
-// with more access rights and must only be used by trusted code.
-// You have to close returned handle using CloseProcessHandle. Returns true
-// on success.
-// TODO(sanjeevr): Replace all calls to OpenPrivilegedProcessHandle with the
-// more specific OpenProcessHandleWithAccess method and delete this.
-BASE_EXPORT bool OpenPrivilegedProcessHandle(ProcessId pid,
-                                             ProcessHandle* handle);
-
 // Converts a PID to a process handle using the desired access flags. Use a
 // combination of the kProcessAccess* flags defined above for |access_flags|.
 BASE_EXPORT bool OpenProcessHandleWithAccess(ProcessId pid,
diff --git a/process/process_handle_posix.cc b/process/process_handle_posix.cc
index 4013254..94b2c2f 100644
--- a/process/process_handle_posix.cc
+++ b/process/process_handle_posix.cc
@@ -23,12 +23,6 @@
   return true;
 }
 
-bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
-  // On POSIX permissions are checked for each operation on process,
-  // not when opening a "handle".
-  return OpenProcessHandle(pid, handle);
-}
-
 bool OpenProcessHandleWithAccess(ProcessId pid,
                                  uint32 access_flags,
                                  ProcessHandle* handle) {
diff --git a/process/process_handle_win.cc b/process/process_handle_win.cc
index 3bc3a12..595d5b0 100644
--- a/process/process_handle_win.cc
+++ b/process/process_handle_win.cc
@@ -36,21 +36,6 @@
   return true;
 }
 
-bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
-  ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
-                                     PROCESS_TERMINATE |
-                                     PROCESS_QUERY_INFORMATION |
-                                     PROCESS_VM_READ |
-                                     SYNCHRONIZE,
-                                     FALSE, pid);
-
-  if (result == NULL)
-    return false;
-
-  *handle = result;
-  return true;
-}
-
 bool OpenProcessHandleWithAccess(ProcessId pid,
                                  uint32 access_flags,
                                  ProcessHandle* handle) {
diff --git a/process/process_linux.cc b/process/process_linux.cc
index 59ee288..cfa3ed5 100644
--- a/process/process_linux.cc
+++ b/process/process_linux.cc
@@ -5,14 +5,21 @@
 #include "base/process/process.h"
 
 #include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
 #include <sys/resource.h>
+#include <sys/syscall.h>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
 
 namespace base {
 
@@ -78,6 +85,52 @@
   bool can_reraise_priority;
 };
 
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+// This function runs on the stack specified on the clone call. It uses longjmp
+// to switch back to the original stack so the child can return from sys_clone.
+int CloneHelper(void* arg) {
+  jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
+  longjmp(*env_ptr, 1);
+
+  // Should not be reached.
+  RAW_CHECK(false);
+  return 1;
+}
+
+// This function is noinline to ensure that stack_buf is below the stack pointer
+// that is saved when setjmp is called below. This is needed because when
+// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
+// upwards. See crbug.com/442912 for more details.
+#if defined(ADDRESS_SANITIZER)
+// Disable AddressSanitizer instrumentation for this function to make sure
+// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
+// Under ASan longjmp() will attempt to clean up the area between the old and
+// new stack pointers and print a warning that may confuse the user.
+__attribute__((no_sanitize_address))
+#endif
+NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags,
+                                      pid_t* ptid,
+                                      pid_t* ctid,
+                                      jmp_buf* env) {
+  // We use the libc clone wrapper instead of making the syscall
+  // directly because making the syscall may fail to update the libc's
+  // internal pid cache. The libc interface unfortunately requires
+  // specifying a new stack, so we use setjmp/longjmp to emulate
+  // fork-like behavior.
+  char stack_buf[PTHREAD_STACK_MIN];
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
+  // The stack grows downward.
+  void* stack = stack_buf + sizeof(stack_buf);
+#else
+#error "Unsupported architecture"
+#endif
+  return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid);
+}
+
 }  // namespace
 
 // static
@@ -136,4 +189,43 @@
   return result == 0;
 }
 
+pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) {
+  const bool clone_tls_used = flags & CLONE_SETTLS;
+  const bool invalid_ctid =
+      (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid;
+  const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid;
+
+  // We do not support CLONE_VM.
+  const bool clone_vm_used = flags & CLONE_VM;
+
+  if (clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used) {
+    RAW_LOG(FATAL, "Invalid usage of ForkWithFlags");
+  }
+
+  // Valgrind's clone implementation does not support specifiying a child_stack
+  // without CLONE_VM, so we cannot use libc's clone wrapper when running under
+  // Valgrind. As a result, the libc pid cache may be incorrect under Valgrind.
+  // See crbug.com/442817 for more details.
+  if (IsRunningOnValgrind()) {
+    // See kernel/fork.c in Linux. There is different ordering of sys_clone
+    // parameters depending on CONFIG_CLONE_BACKWARDS* configuration options.
+#if defined(ARCH_CPU_X86_64)
+    return syscall(__NR_clone, flags, nullptr, ptid, ctid, nullptr);
+#elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)
+    // CONFIG_CLONE_BACKWARDS defined.
+    return syscall(__NR_clone, flags, nullptr, ptid, nullptr, ctid);
+#else
+#error "Unsupported architecture"
+#endif
+  }
+
+  jmp_buf env;
+  if (setjmp(env) == 0) {
+    return CloneAndLongjmpInChild(flags, ptid, ctid, &env);
+  }
+
+  return 0;
+}
+
 }  // namespace base
diff --git a/process/process_posix.cc b/process/process_posix.cc
index 58852bc..93dec98 100644
--- a/process/process_posix.cc
+++ b/process/process_posix.cc
@@ -38,6 +38,16 @@
 }
 
 // static
+Process Process::OpenWithExtraPriviles(ProcessId pid) {
+  if (pid == GetCurrentProcId())
+    return Current();
+
+  // On POSIX process handles are the same as PIDs, and there are no privileges
+  // to set.
+  return Process(pid);
+}
+
+// static
 Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
   DCHECK_NE(handle, GetCurrentProcessHandle());
   return Process(handle);
diff --git a/process/process_unittest.cc b/process/process_unittest.cc
index 5180f64..8130726 100644
--- a/process/process_unittest.cc
+++ b/process/process_unittest.cc
@@ -4,13 +4,27 @@
 
 #include "base/process/process.h"
 
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/posix/eintr_wrapper.h"
 #include "base/process/kill.h"
 #include "base/test/multiprocess_test.h"
 #include "base/test/test_timeouts.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/platform_thread.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
 
+#if defined(OS_LINUX)
+#include <errno.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
 
 namespace {
 
@@ -201,4 +215,105 @@
   EXPECT_EQ(old_priority, new_priority);
 }
 
+#if defined(OS_LINUX)
+const int kSuccess = 0;
+
+MULTIPROCESS_TEST_MAIN(CheckPidProcess) {
+  const pid_t kInitPid = 1;
+  const pid_t pid = syscall(__NR_getpid);
+  CHECK(pid == kInitPid);
+  CHECK(getpid() == pid);
+  return kSuccess;
+}
+
+TEST_F(ProcessTest, CloneFlags) {
+  if (RunningOnValgrind() || !PathExists(FilePath("/proc/self/ns/user")) ||
+      !PathExists(FilePath("/proc/self/ns/pid"))) {
+    // User or PID namespaces are not supported.
+    return;
+  }
+
+  LaunchOptions options;
+  options.clone_flags = CLONE_NEWUSER | CLONE_NEWPID;
+
+  Process process(SpawnChildWithOptions("CheckPidProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(kSuccess, exit_code);
+}
+
+TEST(ForkWithFlagsTest, UpdatesPidCache) {
+  // The libc clone function, which allows ForkWithFlags to keep the pid cache
+  // up to date, does not work on Valgrind.
+  if (RunningOnValgrind()) {
+    return;
+  }
+
+  // Warm up the libc pid cache, if there is one.
+  ASSERT_EQ(syscall(__NR_getpid), getpid());
+
+  pid_t ctid = 0;
+  const pid_t pid = ForkWithFlags(SIGCHLD | CLONE_CHILD_SETTID, nullptr, &ctid);
+  if (pid == 0) {
+    // In child.  Check both the raw getpid syscall and the libc getpid wrapper
+    // (which may rely on a pid cache).
+    RAW_CHECK(syscall(__NR_getpid) == ctid);
+    RAW_CHECK(getpid() == ctid);
+    _exit(kSuccess);
+  }
+
+  ASSERT_NE(-1, pid);
+  int status = 42;
+  ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+  ASSERT_TRUE(WIFEXITED(status));
+  EXPECT_EQ(kSuccess, WEXITSTATUS(status));
+}
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+const char kPipeValue = '\xcc';
+
+class ReadFromPipeDelegate : public LaunchOptions::PreExecDelegate {
+ public:
+  explicit ReadFromPipeDelegate(int fd) : fd_(fd) {}
+  ~ReadFromPipeDelegate() override {}
+  void RunAsyncSafe() override {
+    char c;
+    RAW_CHECK(HANDLE_EINTR(read(fd_, &c, 1)) == 1);
+    RAW_CHECK(IGNORE_EINTR(close(fd_)) == 0);
+    RAW_CHECK(c == kPipeValue);
+  }
+
+ private:
+  int fd_;
+  DISALLOW_COPY_AND_ASSIGN(ReadFromPipeDelegate);
+};
+
+TEST_F(ProcessTest, PreExecHook) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+
+  ScopedFD read_fd(pipe_fds[0]);
+  ScopedFD write_fd(pipe_fds[1]);
+  base::FileHandleMappingVector fds_to_remap;
+  fds_to_remap.push_back(std::make_pair(read_fd.get(), read_fd.get()));
+
+  ReadFromPipeDelegate read_from_pipe_delegate(read_fd.get());
+  LaunchOptions options;
+  options.fds_to_remap = &fds_to_remap;
+  options.pre_exec_delegate = &read_from_pipe_delegate;
+  Process process(SpawnChildWithOptions("SimpleChildProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  read_fd.reset();
+  ASSERT_EQ(1, HANDLE_EINTR(write(write_fd.get(), &kPipeValue, 1)));
+
+  int exit_code = 42;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(0, exit_code);
+}
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
 }  // namespace base
diff --git a/process/process_util_unittest.cc b/process/process_util_unittest.cc
index 80e103d..4b2a575 100644
--- a/process/process_util_unittest.cc
+++ b/process/process_util_unittest.cc
@@ -607,7 +607,7 @@
 #else
   CHECK_EQ(0, clone_flags);
 #endif  // OS_LINUX
-  EXPECT_TRUE(base::LaunchProcess(args, options, NULL));
+  EXPECT_TRUE(base::LaunchProcess(args, options).IsValid());
   PCHECK(IGNORE_EINTR(close(fds[1])) == 0);
 
   char buf[512];
@@ -679,10 +679,8 @@
   // Test a non-trival value for clone_flags.
   // Don't test on Valgrind as it has limited support for clone().
   if (!RunningOnValgrind()) {
-    EXPECT_EQ(
-        "wibble\n",
-        TestLaunchProcess(
-            echo_base_test, env_changes, no_clear_environ, CLONE_FS | SIGCHLD));
+    EXPECT_EQ("wibble\n", TestLaunchProcess(echo_base_test, env_changes,
+                                            no_clear_environ, CLONE_FS));
   }
 
   EXPECT_EQ(
diff --git a/process/process_win.cc b/process/process_win.cc
index 96556a9..2c267aa 100644
--- a/process/process_win.cc
+++ b/process/process_win.cc
@@ -9,6 +9,13 @@
 #include "base/process/kill.h"
 #include "base/win/windows_version.h"
 
+namespace {
+
+DWORD kBasicProcessAccess =
+  PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
+
+} // namespace
+
 namespace base {
 
 Process::Process(ProcessHandle handle)
@@ -40,6 +47,13 @@
 }
 
 // static
+Process Process::OpenWithExtraPriviles(ProcessId pid) {
+  DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
+  ProcessHandle handle = ::OpenProcess(access, FALSE, pid);
+  return Process(handle);
+}
+
+// static
 Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
   DCHECK_NE(handle, ::GetCurrentProcess());
   ProcessHandle out_handle;
diff --git a/stl_util_unittest.cc b/stl_util_unittest.cc
index a3f8e16..06ea7cd 100644
--- a/stl_util_unittest.cc
+++ b/stl_util_unittest.cc
@@ -238,5 +238,30 @@
   EXPECT_TRUE(STLIncludes<std::set<int> >(a3, a2));
 }
 
+TEST(StringAsArrayTest, Empty) {
+  std::string empty;
+  EXPECT_EQ(nullptr, string_as_array(&empty));
+}
+
+TEST(StringAsArrayTest, NullTerminated) {
+  // If any std::string implementation is not null-terminated, this should
+  // fail. All compilers we use return a null-terminated buffer, but please do
+  // not rely on this fact in your code.
+  std::string str("abcde");
+  str.resize(3);
+  EXPECT_STREQ("abc", string_as_array(&str));
+}
+
+TEST(StringAsArrayTest, WriteCopy) {
+  // With a COW implementation, this test will fail if
+  // string_as_array(&str) is implemented as
+  // const_cast<char*>(str->data()).
+  std::string s1("abc");
+  const std::string s2(s1);
+  string_as_array(&s1)[1] = 'x';
+  EXPECT_EQ("axc", s1);
+  EXPECT_EQ("abc", s2);
+}
+
 }  // namespace
 }  // namespace base
diff --git a/test/gtest_util.cc b/test/gtest_util.cc
index 47fd639..f98320c 100644
--- a/test/gtest_util.cc
+++ b/test/gtest_util.cc
@@ -40,4 +40,39 @@
   return serializer.Serialize(root);
 }
 
+bool ReadTestNamesFromFile(const FilePath& path,
+                           std::vector<SplitTestName>* output) {
+  JSONFileValueSerializer deserializer(path);
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<base::Value> value(
+      deserializer.Deserialize(&error_code, &error_message));
+  if (!value.get())
+    return false;
+
+  base::ListValue* tests = nullptr;
+  if (!value->GetAsList(&tests))
+    return false;
+
+  std::vector<base::SplitTestName> result;
+  for (base::ListValue::iterator i = tests->begin(); i != tests->end(); ++i) {
+    base::DictionaryValue* test = nullptr;
+    if (!(*i)->GetAsDictionary(&test))
+      return false;
+
+    std::string test_case_name;
+    if (!test->GetStringASCII("test_case_name", &test_case_name))
+      return false;
+
+    std::string test_name;
+    if (!test->GetStringASCII("test_name", &test_name))
+      return false;
+
+    result.push_back(std::make_pair(test_case_name, test_name));
+  }
+
+  output->swap(result);
+  return true;
+}
+
 }  // namespace
diff --git a/test/gtest_util.h b/test/gtest_util.h
index 93382f8..d10c72f 100644
--- a/test/gtest_util.h
+++ b/test/gtest_util.h
@@ -26,6 +26,12 @@
 // current executable as a JSON file. Returns true on success.
 bool WriteCompiledInTestsToFile(const FilePath& path) WARN_UNUSED_RESULT;
 
+// Reads the list of gtest-based tests from |path| into |output|.
+// Returns true on success.
+bool ReadTestNamesFromFile(
+    const FilePath& path,
+    std::vector<SplitTestName>* output) WARN_UNUSED_RESULT;
+
 }  // namespace base
 
 #endif  // BASE_TEST_GTEST_UTIL_H_
diff --git a/test/launcher/test_launcher.cc b/test/launcher/test_launcher.cc
index af2e461..b5316ad 100644
--- a/test/launcher/test_launcher.cc
+++ b/test/launcher/test_launcher.cc
@@ -829,6 +829,11 @@
     }
   }
 
+  if (!launcher_delegate_->GetTests(&tests_)) {
+    LOG(ERROR) << "Failed to get list of tests.";
+    return false;
+  }
+
   if (!results_tracker_.Init(*command_line)) {
     LOG(ERROR) << "Failed to initialize test results tracker.";
     return 1;
@@ -900,12 +905,10 @@
 }
 
 void TestLauncher::RunTests() {
-  std::vector<SplitTestName> tests(GetCompiledInTests());
-
   std::vector<std::string> test_names;
-
-  for (size_t i = 0; i < tests.size(); i++) {
-    std::string test_name = FormatFullTestName(tests[i].first, tests[i].second);
+  for (size_t i = 0; i < tests_.size(); i++) {
+    std::string test_name = FormatFullTestName(
+        tests_[i].first, tests_[i].second);
 
     results_tracker_.AddTest(test_name);
 
@@ -918,7 +921,7 @@
         continue;
     }
 
-    if (!launcher_delegate_->ShouldRunTest(tests[i].first, tests[i].second))
+    if (!launcher_delegate_->ShouldRunTest(tests_[i].first, tests_[i].second))
       continue;
 
     // Skip the test that doesn't match the filter (if given).
diff --git a/test/launcher/test_launcher.h b/test/launcher/test_launcher.h
index 78a854b..27909d4 100644
--- a/test/launcher/test_launcher.h
+++ b/test/launcher/test_launcher.h
@@ -11,6 +11,7 @@
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
+#include "base/test/gtest_util.h"
 #include "base/test/launcher/test_result.h"
 #include "base/test/launcher/test_results_tracker.h"
 #include "base/time/time.h"
@@ -40,6 +41,10 @@
 // which tests and how are run.
 class TestLauncherDelegate {
  public:
+  // Called to get names of tests available for running. The delegate
+  // must put the result in |output| and return true on success.
+  virtual bool GetTests(std::vector<SplitTestName>* output) = 0;
+
   // Called before a test is considered for running. If it returns false,
   // the test is not run. If it returns true, the test will be run provided
   // it is part of the current shard.
@@ -158,6 +163,9 @@
   std::vector<std::string> positive_test_filter_;
   std::vector<std::string> negative_test_filter_;
 
+  // Tests to use (cached result of TestLauncherDelegate::GetTests).
+  std::vector<SplitTestName> tests_;
+
   // Number of tests started in this iteration.
   size_t test_started_count_;
 
diff --git a/test/launcher/test_launcher_ios.cc b/test/launcher/test_launcher_ios.cc
index 39051ca..82353cc 100644
--- a/test/launcher/test_launcher_ios.cc
+++ b/test/launcher/test_launcher_ios.cc
@@ -5,18 +5,152 @@
 #include "base/test/launcher/test_launcher.h"
 
 #include "base/at_exit.h"
+#include "base/base_paths.h"
 #include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
 #include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
 
 namespace {
 
-int DummyRunTestSuite(void) {
-  return -1;
+const char kHelpFlag[] = "help";
+
+void PrintUsage() {
+  fprintf(stdout,
+          "Runs tests using the gtest framework, each batch of tests being\n"
+          "run in their own process. Supported command-line flags:\n"
+          "\n"
+          " Common flags:\n"
+          "  --gtest_filter=...\n"
+          "    Runs a subset of tests (see --gtest_help for more info).\n"
+          "\n"
+          "  --help\n"
+          "    Shows this message.\n"
+          "\n"
+          " Other flags:\n"
+          "  --test-launcher-retry-limit=N\n"
+          "    Sets the limit of test retries on failures to N.\n"
+          "\n"
+          "  --test-launcher-summary-output=PATH\n"
+          "    Saves a JSON machine-readable summary of the run.\n"
+          "\n"
+          "  --test-launcher-print-test-stdio=auto|always|never\n"
+          "    Controls when full test output is printed.\n"
+          "    auto means to print it when the test failed.\n"
+          "\n"
+          "  --test-launcher-total-shards=N\n"
+          "    Sets the total number of shards to N.\n"
+          "\n"
+          "  --test-launcher-shard-index=N\n"
+          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
+  fflush(stdout);
 }
 
+class IOSUnitTestLauncherDelegate : public base::UnitTestLauncherDelegate {
+ public:
+  IOSUnitTestLauncherDelegate() : base::UnitTestLauncherDelegate(0, false) {
+  }
+
+  bool Init() WARN_UNUSED_RESULT {
+    if (!PathService::Get(base::DIR_EXE, &dir_exe_)) {
+      LOG(ERROR) << "Failed to get directory of current executable.";
+      return false;
+    }
+
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    std::vector<std::string> args(command_line->GetArgs());
+    if (args.size() < 1) {
+      LOG(ERROR) << "Arguments expected.";
+      return false;
+    }
+    test_name_ = args[0];
+
+    base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
+    cmd_line.AppendSwitch(switches::kTestLauncherPrintWritablePath);
+    cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value());
+
+    std::string raw_output;
+    if (!base::GetAppOutput(cmd_line, &raw_output)) {
+      LOG(ERROR) << "GetAppOutput failed.";
+      return false;
+    }
+    writable_path_ = base::FilePath(raw_output);
+
+    return true;
+  }
+
+  bool GetTests(std::vector<base::SplitTestName>* output) override {
+    base::ScopedTempDir temp_dir;
+    if (!temp_dir.CreateUniqueTempDirUnderPath(writable_path_))
+      return false;
+    base::FilePath test_list_path(
+        temp_dir.path().AppendASCII("test_list.json"));
+
+    base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
+    cmd_line.AppendSwitchPath(switches::kTestLauncherListTests, test_list_path);
+    cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value());
+
+    base::LaunchOptions launch_options;
+    launch_options.wait = true;
+
+    if (!base::LaunchProcess(cmd_line, launch_options).IsValid())
+      return false;
+
+    return base::ReadTestNamesFromFile(test_list_path, output);
+  }
+
+ private:
+  // Directory containing test launcher's executable.
+  base::FilePath dir_exe_;
+
+  // Name of the test executable to run.
+  std::string test_name_;
+
+  // Path that launched test binary can write to.
+  base::FilePath writable_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSUnitTestLauncherDelegate);
+};
+
 }  // namespace
 
 int main(int argc, char** argv) {
   base::AtExitManager at_exit;
-  return base::LaunchUnitTests(argc, argv, base::Bind(&DummyRunTestSuite));
+
+  base::CommandLine::Init(argc, argv);
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
+    PrintUsage();
+    return 0;
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  TestTimeouts::Initialize();
+
+  base::MessageLoopForIO message_loop;
+
+  IOSUnitTestLauncherDelegate delegate;
+  if (!delegate.Init()) {
+    fprintf(stderr, "Failed to intialize test launcher delegate.\n");
+    fflush(stderr);
+    return 1;
+  }
+  // Force one job since we can't run multiple simulators in parallel.
+  base::TestLauncher launcher(&delegate, 1);
+  bool success = launcher.Run();
+
+  fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+
+  return (success ? 0 : 1);
 }
diff --git a/test/launcher/unit_test_launcher.cc b/test/launcher/unit_test_launcher.cc
index 6309cde..9a8b41f 100644
--- a/test/launcher/unit_test_launcher.cc
+++ b/test/launcher/unit_test_launcher.cc
@@ -100,34 +100,159 @@
   return new_cmd_line;
 }
 
-class UnitTestLauncherDelegate : public TestLauncherDelegate {
- public:
-  explicit UnitTestLauncherDelegate(size_t batch_limit, bool use_job_objects)
-      : batch_limit_(batch_limit),
-        use_job_objects_(use_job_objects) {
+bool GetSwitchValueAsInt(const std::string& switch_name, int* result) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switch_name))
+    return true;
+
+  std::string switch_value =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name);
+  if (!StringToInt(switch_value, result) || *result < 1) {
+    LOG(ERROR) << "Invalid value for " << switch_name << ": " << switch_value;
+    return false;
   }
 
-  ~UnitTestLauncherDelegate() override {
-    DCHECK(thread_checker_.CalledOnValidThread());
+  return true;
+}
+
+int LaunchUnitTestsInternal(const RunTestSuiteCallback& run_test_suite,
+                            int default_jobs,
+                            bool use_job_objects,
+                            const Closure& gtest_init) {
+#if defined(OS_ANDROID)
+  // We can't easily fork on Android, just run the test suite directly.
+  return run_test_suite.Run();
+#else
+  bool force_single_process = false;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestLauncherDebugLauncher)) {
+    fprintf(stdout, "Forcing test launcher debugging mode.\n");
+    fflush(stdout);
+  } else {
+    if (base::debug::BeingDebugged()) {
+      fprintf(stdout,
+              "Debugger detected, switching to single process mode.\n"
+              "Pass --test-launcher-debug-launcher to debug the launcher "
+              "itself.\n");
+      fflush(stdout);
+      force_single_process = true;
+    }
   }
 
- private:
-  struct GTestCallbackState {
-    TestLauncher* test_launcher;
-    std::vector<std::string> test_names;
-    FilePath output_file;
-  };
+  if (CommandLine::ForCurrentProcess()->HasSwitch(kGTestHelpFlag) ||
+      CommandLine::ForCurrentProcess()->HasSwitch(kGTestListTestsFlag) ||
+      CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
+      force_single_process) {
+    return run_test_suite.Run();
+  }
+#endif
 
-  bool ShouldRunTest(const std::string& test_case_name,
-                     const std::string& test_name) override {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
+    PrintUsage();
+    return 0;
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  gtest_init.Run();
+  TestTimeouts::Initialize();
+
+  int batch_limit = kDefaultTestBatchLimit;
+  if (!GetSwitchValueAsInt(switches::kTestLauncherBatchLimit, &batch_limit))
+    return 1;
+
+  fprintf(stdout,
+          "IMPORTANT DEBUGGING NOTE: batches of tests are run inside their\n"
+          "own process. For debugging a test inside a debugger, use the\n"
+          "--gtest_filter=<your_test_name> flag along with\n"
+          "--single-process-tests.\n");
+  fflush(stdout);
+
+  MessageLoopForIO message_loop;
+
+  UnitTestLauncherDelegate delegate(batch_limit, use_job_objects);
+  base::TestLauncher launcher(&delegate, default_jobs);
+  bool success = launcher.Run();
+
+  fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+
+  return (success ? 0 : 1);
+}
+
+void InitGoogleTestChar(int* argc, char** argv) {
+  testing::InitGoogleTest(argc, argv);
+}
+
+#if defined(OS_WIN)
+void InitGoogleTestWChar(int* argc, wchar_t** argv) {
+  testing::InitGoogleTest(argc, argv);
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CommandLine::Init(argc, argv);
+  return LaunchUnitTestsInternal(run_test_suite, SysInfo::NumberOfProcessors(),
+                                 true, Bind(&InitGoogleTestChar, &argc, argv));
+}
+
+int LaunchUnitTestsSerially(int argc,
+                            char** argv,
+                            const RunTestSuiteCallback& run_test_suite) {
+  CommandLine::Init(argc, argv);
+  return LaunchUnitTestsInternal(run_test_suite, 1, true,
+                                 Bind(&InitGoogleTestChar, &argc, argv));
+}
+
+#if defined(OS_WIN)
+int LaunchUnitTests(int argc,
+                    wchar_t** argv,
+                    bool use_job_objects,
+                    const RunTestSuiteCallback& run_test_suite) {
+  // Windows CommandLine::Init ignores argv anyway.
+  CommandLine::Init(argc, NULL);
+  return LaunchUnitTestsInternal(run_test_suite, SysInfo::NumberOfProcessors(),
+                                 use_job_objects,
+                                 Bind(&InitGoogleTestWChar, &argc, argv));
+}
+#endif  // defined(OS_WIN)
+
+UnitTestLauncherDelegate::UnitTestLauncherDelegate(size_t batch_limit,
+                                                   bool use_job_objects)
+    : batch_limit_(batch_limit), use_job_objects_(use_job_objects) {
+}
+
+UnitTestLauncherDelegate::~UnitTestLauncherDelegate() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+UnitTestLauncherDelegate::GTestCallbackState::GTestCallbackState() {
+}
+
+UnitTestLauncherDelegate::GTestCallbackState::~GTestCallbackState() {
+}
+
+bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  *output = GetCompiledInTests();
+  return true;
+}
+
+bool UnitTestLauncherDelegate::ShouldRunTest(const std::string& test_case_name,
+                                             const std::string& test_name) {
     DCHECK(thread_checker_.CalledOnValidThread());
 
     // There is no additional logic to disable specific tests.
     return true;
   }
 
-  size_t RunTests(TestLauncher* test_launcher,
-                  const std::vector<std::string>& test_names) override {
+  size_t UnitTestLauncherDelegate::RunTests(
+      TestLauncher* test_launcher,
+      const std::vector<std::string>& test_names) {
     DCHECK(thread_checker_.CalledOnValidThread());
 
     std::vector<std::string> batch;
@@ -145,8 +270,9 @@
     return test_names.size();
   }
 
-  size_t RetryTests(TestLauncher* test_launcher,
-                    const std::vector<std::string>& test_names) override {
+  size_t UnitTestLauncherDelegate::RetryTests(
+      TestLauncher* test_launcher,
+      const std::vector<std::string>& test_names) {
     MessageLoop::current()->PostTask(
         FROM_HERE,
         Bind(&UnitTestLauncherDelegate::RunSerially,
@@ -156,8 +282,9 @@
     return test_names.size();
   }
 
-  void RunSerially(TestLauncher* test_launcher,
-                   const std::vector<std::string>& test_names) {
+  void UnitTestLauncherDelegate::RunSerially(
+      TestLauncher* test_launcher,
+      const std::vector<std::string>& test_names) {
     if (test_names.empty())
       return;
 
@@ -193,8 +320,9 @@
              new_test_names));
   }
 
-  void RunBatch(TestLauncher* test_launcher,
-                const std::vector<std::string>& test_names) {
+  void UnitTestLauncherDelegate::RunBatch(
+      TestLauncher* test_launcher,
+      const std::vector<std::string>& test_names) {
     DCHECK(thread_checker_.CalledOnValidThread());
 
     if (test_names.empty())
@@ -234,11 +362,12 @@
              callback_state));
   }
 
-  void GTestCallback(const GTestCallbackState& callback_state,
-                     int exit_code,
-                     const TimeDelta& elapsed_time,
-                     bool was_timeout,
-                     const std::string& output) {
+  void UnitTestLauncherDelegate::GTestCallback(
+      const GTestCallbackState& callback_state,
+      int exit_code,
+      const TimeDelta& elapsed_time,
+      bool was_timeout,
+      const std::string& output) {
     DCHECK(thread_checker_.CalledOnValidThread());
     std::vector<std::string> tests_to_relaunch;
     ProcessTestResults(callback_state.test_launcher,
@@ -262,12 +391,13 @@
     DeleteFile(callback_state.output_file.DirName(), true);
   }
 
-  void SerialGTestCallback(const GTestCallbackState& callback_state,
-                           const std::vector<std::string>& test_names,
-                           int exit_code,
-                           const TimeDelta& elapsed_time,
-                           bool was_timeout,
-                           const std::string& output) {
+  void UnitTestLauncherDelegate::SerialGTestCallback(
+      const GTestCallbackState& callback_state,
+      const std::vector<std::string>& test_names,
+      int exit_code,
+      const TimeDelta& elapsed_time,
+      bool was_timeout,
+      const std::string& output) {
     DCHECK(thread_checker_.CalledOnValidThread());
     std::vector<std::string> tests_to_relaunch;
     bool called_any_callbacks =
@@ -297,7 +427,8 @@
              test_names));
   }
 
-  static bool ProcessTestResults(
+  // static
+  bool UnitTestLauncherDelegate::ProcessTestResults(
       TestLauncher* test_launcher,
       const std::vector<std::string>& test_names,
       const base::FilePath& output_file,
@@ -434,143 +565,4 @@
     return called_any_callback;
   }
 
-  ThreadChecker thread_checker_;
-
-  // Maximum number of tests to run in a single batch.
-  size_t batch_limit_;
-
-  // Determines whether we use job objects on Windows.
-  bool use_job_objects_;
-};
-
-bool GetSwitchValueAsInt(const std::string& switch_name, int* result) {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switch_name))
-    return true;
-
-  std::string switch_value =
-      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name);
-  if (!StringToInt(switch_value, result) || *result < 1) {
-    LOG(ERROR) << "Invalid value for " << switch_name << ": " << switch_value;
-    return false;
-  }
-
-  return true;
-}
-
-int LaunchUnitTestsInternal(const RunTestSuiteCallback& run_test_suite,
-                            int default_jobs,
-                            bool use_job_objects,
-                            const Closure& gtest_init) {
-#if defined(OS_ANDROID)
-  // We can't easily fork on Android, just run the test suite directly.
-  return run_test_suite.Run();
-#else
-  bool force_single_process = false;
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kTestLauncherDebugLauncher)) {
-    fprintf(stdout, "Forcing test launcher debugging mode.\n");
-    fflush(stdout);
-  } else {
-    if (base::debug::BeingDebugged()) {
-      fprintf(stdout,
-              "Debugger detected, switching to single process mode.\n"
-              "Pass --test-launcher-debug-launcher to debug the launcher "
-              "itself.\n");
-      fflush(stdout);
-      force_single_process = true;
-    }
-  }
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(kGTestHelpFlag) ||
-      CommandLine::ForCurrentProcess()->HasSwitch(kGTestListTestsFlag) ||
-      CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
-      force_single_process) {
-    return run_test_suite.Run();
-  }
-#endif
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
-    PrintUsage();
-    return 0;
-  }
-
-  base::TimeTicks start_time(base::TimeTicks::Now());
-
-  gtest_init.Run();
-  TestTimeouts::Initialize();
-
-  int batch_limit = kDefaultTestBatchLimit;
-  if (!GetSwitchValueAsInt(switches::kTestLauncherBatchLimit, &batch_limit))
-    return 1;
-
-  fprintf(stdout,
-          "IMPORTANT DEBUGGING NOTE: batches of tests are run inside their\n"
-          "own process. For debugging a test inside a debugger, use the\n"
-          "--gtest_filter=<your_test_name> flag along with\n"
-          "--single-process-tests.\n");
-  fflush(stdout);
-
-  MessageLoopForIO message_loop;
-
-  UnitTestLauncherDelegate delegate(batch_limit, use_job_objects);
-  base::TestLauncher launcher(&delegate, default_jobs);
-  bool success = launcher.Run();
-
-  fprintf(stdout,
-          "Tests took %" PRId64 " seconds.\n",
-          (base::TimeTicks::Now() - start_time).InSeconds());
-  fflush(stdout);
-
-  return (success ? 0 : 1);
-}
-
-void InitGoogleTestChar(int* argc, char** argv) {
-  testing::InitGoogleTest(argc, argv);
-}
-
-#if defined(OS_WIN)
-void InitGoogleTestWChar(int* argc, wchar_t** argv) {
-  testing::InitGoogleTest(argc, argv);
-}
-#endif  // defined(OS_WIN)
-
-}  // namespace
-
-int LaunchUnitTests(int argc,
-                    char** argv,
-                    const RunTestSuiteCallback& run_test_suite) {
-  CommandLine::Init(argc, argv);
-  return LaunchUnitTestsInternal(
-      run_test_suite,
-      SysInfo::NumberOfProcessors(),
-      true,
-      Bind(&InitGoogleTestChar, &argc, argv));
-}
-
-int LaunchUnitTestsSerially(int argc,
-                            char** argv,
-                            const RunTestSuiteCallback& run_test_suite) {
-  CommandLine::Init(argc, argv);
-  return LaunchUnitTestsInternal(
-      run_test_suite,
-      1,
-      true,
-      Bind(&InitGoogleTestChar, &argc, argv));
-}
-
-#if defined(OS_WIN)
-int LaunchUnitTests(int argc,
-                    wchar_t** argv,
-                    bool use_job_objects,
-                    const RunTestSuiteCallback& run_test_suite) {
-  // Windows CommandLine::Init ignores argv anyway.
-  CommandLine::Init(argc, NULL);
-  return LaunchUnitTestsInternal(
-      run_test_suite,
-      SysInfo::NumberOfProcessors(),
-      use_job_objects,
-      Bind(&InitGoogleTestWChar, &argc, argv));
-}
-#endif  // defined(OS_WIN)
-
 }  // namespace base
diff --git a/test/launcher/unit_test_launcher.h b/test/launcher/unit_test_launcher.h
index 5682ed9..0f661db 100644
--- a/test/launcher/unit_test_launcher.h
+++ b/test/launcher/unit_test_launcher.h
@@ -6,6 +6,8 @@
 #define BASE_TEST_LAUNCHER_UNIT_TEST_LAUNCHER_H_
 
 #include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/test/launcher/test_launcher.h"
 
 namespace base {
 
@@ -31,6 +33,75 @@
                     const RunTestSuiteCallback& run_test_suite);
 #endif  // defined(OS_WIN)
 
+// Test launcher delegate for unit tests (mostly to support batching).
+class UnitTestLauncherDelegate : public TestLauncherDelegate {
+ public:
+  explicit UnitTestLauncherDelegate(size_t batch_limit, bool use_job_objects);
+  ~UnitTestLauncherDelegate() override;
+
+ private:
+  struct GTestCallbackState {
+    GTestCallbackState();
+    ~GTestCallbackState();
+
+    TestLauncher* test_launcher;
+    std::vector<std::string> test_names;
+    FilePath output_file;
+  };
+
+  // TestLauncherDelegate:
+  bool GetTests(std::vector<SplitTestName>* output) override;
+  bool ShouldRunTest(const std::string& test_case_name,
+                     const std::string& test_name) override;
+  size_t RunTests(TestLauncher* test_launcher,
+                  const std::vector<std::string>& test_names) override;
+  size_t RetryTests(TestLauncher* test_launcher,
+                    const std::vector<std::string>& test_names) override;
+
+  // Runs tests serially, each in its own process.
+  void RunSerially(TestLauncher* test_launcher,
+                   const std::vector<std::string>& test_names);
+
+  // Runs tests in batches (each batch in its own process).
+  void RunBatch(TestLauncher* test_launcher,
+                const std::vector<std::string>& test_names);
+
+  // Callback for batched tests.
+  void GTestCallback(const GTestCallbackState& callback_state,
+                     int exit_code,
+                     const TimeDelta& elapsed_time,
+                     bool was_timeout,
+                     const std::string& output);
+
+  // Callback for serialized tests.
+  void SerialGTestCallback(const GTestCallbackState& callback_state,
+                           const std::vector<std::string>& test_names,
+                           int exit_code,
+                           const TimeDelta& elapsed_time,
+                           bool was_timeout,
+                           const std::string& output);
+
+  // Interprets test results and reports to the test launcher. Returns true
+  // on success.
+  static bool ProcessTestResults(TestLauncher* test_launcher,
+                                 const std::vector<std::string>& test_names,
+                                 const base::FilePath& output_file,
+                                 const std::string& output,
+                                 int exit_code,
+                                 bool was_timeout,
+                                 std::vector<std::string>* tests_to_relaunch);
+
+  ThreadChecker thread_checker_;
+
+  // Maximum number of tests to run in a single batch.
+  size_t batch_limit_;
+
+  // Determines whether we use job objects on Windows.
+  bool use_job_objects_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnitTestLauncherDelegate);
+};
+
 }   // namespace base
 
 #endif  // BASE_TEST_LAUNCHER_UNIT_TEST_LAUNCHER_H_
diff --git a/test/launcher/unit_test_launcher_ios.cc b/test/launcher/unit_test_launcher_ios.cc
index d4276c8..acb6c71 100644
--- a/test/launcher/unit_test_launcher_ios.cc
+++ b/test/launcher/unit_test_launcher_ios.cc
@@ -6,7 +6,9 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/mac/foundation_util.h"
 #include "base/test/gtest_util.h"
 #include "base/test/test_switches.h"
 
@@ -27,6 +29,11 @@
       LOG(ERROR) << "Failed to write list of tests.";
       return 1;
     }
+  } else if (command_line->HasSwitch(
+                 switches::kTestLauncherPrintWritablePath)) {
+    fprintf(stdout, "%s", mac::GetUserLibraryPath().value().c_str());
+    fflush(stdout);
+    return 0;
   }
 
   return run_test_suite.Run();
diff --git a/test/test_suite.cc b/test/test_suite.cc
index 383b82c..a6fc201 100644
--- a/test/test_suite.cc
+++ b/test/test_suite.cc
@@ -135,12 +135,12 @@
   testing::GTEST_FLAG(catch_exceptions) = false;
 #endif
   base::EnableTerminationOnHeapCorruption();
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
+#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
   // default. In the gtk code (below) gtk_init() implicitly sets a locale.
   setlocale(LC_ALL, "");
-#endif  // defined(OS_LINUX) && !defined(OS_ANDROID)
+#endif  // defined(OS_LINUX) && defined(USE_AURA)
 
   // On Android, AtExitManager is created in
   // testing/android/native_test_wrapper.cc before main() is called.
diff --git a/test/test_switches.cc b/test/test_switches.cc
index 4d8331d..84aa53c 100644
--- a/test/test_switches.cc
+++ b/test/test_switches.cc
@@ -42,6 +42,10 @@
 const char switches::kTestLauncherPrintTestStdio[] =
     "test-launcher-print-test-stdio";
 
+// Print a writable path and exit (for internal use).
+const char switches::kTestLauncherPrintWritablePath[] =
+    "test-launcher-print-writable-path";
+
 // Index of the test shard to run, starting from 0 (first shard) to total shards
 // minus one (last shard).
 const char switches::kTestLauncherShardIndex[] =
diff --git a/test/test_switches.h b/test/test_switches.h
index 336d036..f145f1e 100644
--- a/test/test_switches.h
+++ b/test/test_switches.h
@@ -19,6 +19,7 @@
 extern const char kTestLauncherRetryLimit[];
 extern const char kTestLauncherSummaryOutput[];
 extern const char kTestLauncherPrintTestStdio[];
+extern const char kTestLauncherPrintWritablePath[];
 extern const char kTestLauncherShardIndex[];
 extern const char kTestLauncherTotalShards[];
 extern const char kTestLauncherTimeout[];
diff --git a/test/test_timeouts.cc b/test/test_timeouts.cc
index 66ae85e..b30d6c3 100644
--- a/test/test_timeouts.cc
+++ b/test/test_timeouts.cc
@@ -23,7 +23,7 @@
 #elif defined(ADDRESS_SANITIZER) && defined(OS_WIN)
 // Asan/Win has not been optimized yet, give it a higher
 // timeout multiplier. See http://crbug.com/412471
-static const int kTimeoutMultiplier = 8;
+static const int kTimeoutMultiplier = 3;
 #elif defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
     defined(SYZYASAN)
 static const int kTimeoutMultiplier = 2;
diff --git a/time/time.h b/time/time.h
index d61a351..915eac8 100644
--- a/time/time.h
+++ b/time/time.h
@@ -100,6 +100,15 @@
     return delta_;
   }
 
+  // Returns the magnitude (absolute value) of this TimeDelta.
+  TimeDelta magnitude() const {
+    // Some toolchains provide an incomplete C++11 implementation and lack an
+    // int64 overload for std::abs().  The following is a simple branchless
+    // implementation:
+    const int64 mask = delta_ >> (sizeof(delta_) * 8 - 1);
+    return TimeDelta((delta_ + mask) ^ mask);
+  }
+
   // Returns true if the time delta is the maximum time delta.
   bool is_max() const {
     return delta_ == std::numeric_limits<int64>::max();
@@ -588,18 +597,26 @@
   TimeTicks() : ticks_(0) {
   }
 
-  // Platform-dependent tick count representing "right now."
-  // The resolution of this clock is ~1-15ms.  Resolution varies depending
-  // on hardware/operating system configuration.
+  // Platform-dependent tick count representing "right now." When
+  // IsHighResolution() returns false, the resolution of the clock could be
+  // as coarse as ~15.6ms. Otherwise, the resolution should be no worse than one
+  // microsecond.
   static TimeTicks Now();
 
-  // Returns a platform-dependent high-resolution tick count. Implementation
-  // is hardware dependent and may or may not return sub-millisecond
-  // resolution.  THIS CALL IS GENERALLY MUCH MORE EXPENSIVE THAN Now() AND
-  // SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
-  static TimeTicks HighResNow();
+  // DEPRECATED
+  // TODO(miu): Remove this function, and all callpoints should call Now().
+  static TimeTicks HighResNow() { return TimeTicks::Now(); }
 
-  static bool IsHighResNowFastAndReliable();
+  // Returns true if the high resolution clock is working on this system and
+  // Now() will return high resolution values. Note that, on systems where the
+  // high resolution clock works but is deemed inefficient, the low resolution
+  // clock will be used instead.
+  static bool IsHighResolution();
+
+  // DEPRECATED
+  // TODO(miu): Remove this function, and all callpoints should call
+  // IsHighResolution().
+  static bool IsHighResNowFastAndReliable() { return IsHighResolution(); }
 
   // Returns true if ThreadNow() is supported on this system.
   static bool IsThreadNowSupported() {
@@ -616,24 +633,33 @@
   // to (approximately) measure how much time the calling thread spent doing
   // actual work vs. being de-scheduled. May return bogus results if the thread
   // migrates to another CPU between two calls.
+  //
+  // WARNING: The returned value might NOT have the same origin as Now(). Do not
+  // perform math between TimeTicks values returned by Now() and ThreadNow() and
+  // expect meaningful results.
+  // TODO(miu): Since the timeline of these values is different, the values
+  // should be of a different type.
   static TimeTicks ThreadNow();
 
-  // Returns the current system trace time or, if none is defined, the current
-  // high-res time (i.e. HighResNow()). On systems where a global trace clock
-  // is defined, timestamping TraceEvents's with this value guarantees
-  // synchronization between events collected inside chrome and events
-  // collected outside (e.g. kernel, X server).
+  // Returns the current system trace time or, if not available on this
+  // platform, a high-resolution time value; or a low-resolution time value if
+  // neither are avalable. On systems where a global trace clock is defined,
+  // timestamping TraceEvents's with this value guarantees synchronization
+  // between events collected inside chrome and events collected outside
+  // (e.g. kernel, X server).
+  //
+  // WARNING: The returned value might NOT have the same origin as Now(). Do not
+  // perform math between TimeTicks values returned by Now() and
+  // NowFromSystemTraceTime() and expect meaningful results.
+  // TODO(miu): Since the timeline of these values is different, the values
+  // should be of a different type.
   static TimeTicks NowFromSystemTraceTime();
 
 #if defined(OS_WIN)
-  // Get the absolute value of QPC time drift. For testing.
-  static int64 GetQPCDriftMicroseconds();
-
+  // Translates an absolute QPC timestamp into a TimeTicks value. The returned
+  // value has the same origin as Now(). Do NOT attempt to use this if
+  // IsHighResolution() returns false.
   static TimeTicks FromQPCValue(LONGLONG qpc_value);
-
-  // Returns true if the high resolution clock is working on this system.
-  // This is only for testing.
-  static bool IsHighResClockWorking();
 #endif
 
   // Returns true if this object has not been initialized.
diff --git a/time/time_mac.cc b/time/time_mac.cc
index 26c5d7a..3944d06 100644
--- a/time/time_mac.cc
+++ b/time/time_mac.cc
@@ -219,12 +219,7 @@
 }
 
 // static
-TimeTicks TimeTicks::HighResNow() {
-  return Now();
-}
-
-// static
-bool TimeTicks::IsHighResNowFastAndReliable() {
+bool TimeTicks::IsHighResolution() {
   return true;
 }
 
diff --git a/time/time_posix.cc b/time/time_posix.cc
index ad00c51..34b2f5a 100644
--- a/time/time_posix.cc
+++ b/time/time_posix.cc
@@ -314,12 +314,7 @@
 }
 
 // static
-TimeTicks TimeTicks::HighResNow() {
-  return Now();
-}
-
-// static
-bool TimeTicks::IsHighResNowFastAndReliable() {
+bool TimeTicks::IsHighResolution() {
   return true;
 }
 
diff --git a/time/time_unittest.cc b/time/time_unittest.cc
index 16d6fe9..07b1e6b 100644
--- a/time/time_unittest.cc
+++ b/time/time_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <time.h>
 
+#include <limits>
 #include <string>
 
 #include "base/compiler_specific.h"
@@ -642,12 +643,10 @@
 }
 
 static void HighResClockTest(TimeTicks (*GetTicks)()) {
-#if defined(OS_WIN)
   // HighResNow doesn't work on some systems.  Since the product still works
   // even if it doesn't work, it makes this entire test questionable.
-  if (!TimeTicks::IsHighResClockWorking())
+  if (!TimeTicks::IsHighResolution())
     return;
-#endif
 
   // Why do we loop here?
   // We're trying to measure that intervals increment in a VERY small amount
@@ -792,6 +791,26 @@
   return oss.str();
 }
 
+TEST(TimeDelta, Magnitude) {
+  const int64 zero = 0;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(zero),
+            TimeDelta::FromMicroseconds(zero).magnitude());
+
+  const int64 one = 1;
+  const int64 negative_one = -1;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+            TimeDelta::FromMicroseconds(one).magnitude());
+  EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+            TimeDelta::FromMicroseconds(negative_one).magnitude());
+
+  const int64 max_int64_minus_one = std::numeric_limits<int64>::max() - 1;
+  const int64 min_int64_plus_two = std::numeric_limits<int64>::min() + 2;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
+            TimeDelta::FromMicroseconds(max_int64_minus_one).magnitude());
+  EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
+            TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude());
+}
+
 TEST(TimeDeltaLogging, DCheckEqCompiles) {
   DCHECK_EQ(TimeDelta(), TimeDelta());
 }
diff --git a/time/time_win.cc b/time/time_win.cc
index 9b4f17d..8ae7640 100644
--- a/time/time_win.cc
+++ b/time/time_win.cc
@@ -307,13 +307,13 @@
   return timeGetTime();
 }
 
-DWORD (*tick_function)(void) = &timeGetTimeWrapper;
+DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
 
 // Accumulation of time lost due to rollover (in milliseconds).
-int64 rollover_ms = 0;
+int64 g_rollover_ms = 0;
 
 // The last timeGetTime value we saw, to detect rollover.
-DWORD last_seen_now = 0;
+DWORD g_last_seen_now = 0;
 
 // Lock protecting rollover_ms and last_seen_now.
 // Note: this is a global object, and we usually avoid these. However, the time
@@ -321,169 +321,161 @@
 // easy to use a Singleton without even knowing it, and that may lead to many
 // gotchas). Its impact on startup time should be negligible due to low-level
 // nature of time code.
-base::Lock rollover_lock;
+base::Lock g_rollover_lock;
 
 // We use timeGetTime() to implement TimeTicks::Now().  This can be problematic
 // because it returns the number of milliseconds since Windows has started,
 // which will roll over the 32-bit value every ~49 days.  We try to track
 // rollover ourselves, which works if TimeTicks::Now() is called at least every
 // 49 days.
-TimeDelta RolloverProtectedNow() {
-  base::AutoLock locked(rollover_lock);
+TimeTicks RolloverProtectedNow() {
+  base::AutoLock locked(g_rollover_lock);
   // We should hold the lock while calling tick_function to make sure that
   // we keep last_seen_now stay correctly in sync.
-  DWORD now = tick_function();
-  if (now < last_seen_now)
-    rollover_ms += 0x100000000I64;  // ~49.7 days.
-  last_seen_now = now;
-  return TimeDelta::FromMilliseconds(now + rollover_ms);
+  DWORD now = g_tick_function();
+  if (now < g_last_seen_now)
+    g_rollover_ms += 0x100000000I64;  // ~49.7 days.
+  g_last_seen_now = now;
+  return TimeTicks() + TimeDelta::FromMilliseconds(now + g_rollover_ms);
 }
 
-bool IsBuggyAthlon(const base::CPU& cpu) {
-  // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
-  // unreliable.  Fallback to low-res clock.
-  return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
-}
-
-// Overview of time counters:
+// Discussion of tick counter options on Windows:
+//
 // (1) CPU cycle counter. (Retrieved via RDTSC)
 // The CPU counter provides the highest resolution time stamp and is the least
-// expensive to retrieve. However, the CPU counter is unreliable and should not
-// be used in production. Its biggest issue is that it is per processor and it
-// is not synchronized between processors. Also, on some computers, the counters
-// will change frequency due to thermal and power changes, and stop in some
-// states.
+// expensive to retrieve. However, on older CPUs, two issues can affect its
+// reliability: First it is maintained per processor and not synchronized
+// between processors. Also, the counters will change frequency due to thermal
+// and power changes, and stop in some states.
 //
 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
-// resolution (100 nanoseconds) time stamp but is comparatively more expensive
-// to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
-// (with some help from ACPI).
-// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
-// in the worst case, it gets the counter from the rollover interrupt on the
+// resolution (<1 microsecond) time stamp. On most hardware running today, it
+// auto-detects and uses the constant-rate RDTSC counter to provide extremely
+// efficient and reliable time stamps.
+//
+// On older CPUs where RDTSC is unreliable, it falls back to using more
+// expensive (20X to 40X more costly) alternate clocks, such as HPET or the ACPI
+// PM timer, and can involve system calls; and all this is up to the HAL (with
+// some help from ACPI). According to
+// http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx, in the
+// worst case, it gets the counter from the rollover interrupt on the
 // programmable interrupt timer. In best cases, the HAL may conclude that the
 // RDTSC counter runs at a constant frequency, then it uses that instead. On
 // multiprocessor machines, it will try to verify the values returned from
 // RDTSC on each processor are consistent with each other, and apply a handful
 // of workarounds for known buggy hardware. In other words, QPC is supposed to
-// give consistent result on a multiprocessor computer, but it is unreliable in
-// reality due to bugs in BIOS or HAL on some, especially old computers.
-// With recent updates on HAL and newer BIOS, QPC is getting more reliable but
-// it should be used with caution.
+// give consistent results on a multiprocessor computer, but for older CPUs it
+// can be unreliable due bugs in BIOS or HAL.
 //
-// (3) System time. The system time provides a low-resolution (typically 10ms
-// to 55 milliseconds) time stamp but is comparatively less expensive to
-// retrieve and more reliable.
-class HighResNowSingleton {
- public:
-  HighResNowSingleton()
-      : ticks_per_second_(0),
-        skew_(0) {
+// (3) System time. The system time provides a low-resolution (from ~1 to ~15.6
+// milliseconds) time stamp but is comparatively less expensive to retrieve and
+// more reliable. Time::EnableHighResolutionTimer() and
+// Time::ActivateHighResolutionTimer() can be called to alter the resolution of
+// this timer; and also other Windows applications can alter it, affecting this
+// one.
 
-    base::CPU cpu;
-    if (IsBuggyAthlon(cpu))
-      return;
+using NowFunction = TimeTicks (*)(void);
 
-    // Synchronize the QPC clock with GetSystemTimeAsFileTime.
-    LARGE_INTEGER ticks_per_sec = {0};
-    if (!QueryPerformanceFrequency(&ticks_per_sec))
-      return; // QPC is not available.
-    ticks_per_second_ = ticks_per_sec.QuadPart;
+TimeTicks InitialNowFunction();
+TimeTicks InitialSystemTraceNowFunction();
 
-    skew_ = UnreliableNow() - ReliableNow();
+// See "threading notes" in InitializeNowFunctionPointers() for details on how
+// concurrent reads/writes to these globals has been made safe.
+NowFunction g_now_function = &InitialNowFunction;
+NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction;
+int64 g_qpc_ticks_per_second = 0;
+
+// As of January 2015, use of <atomic> is forbidden in Chromium code. This is
+// what std::atomic_thread_fence does on Windows on all Intel architectures when
+// the memory_order argument is anything but std::memory_order_seq_cst:
+#define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
+
+TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
+  // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
+  // InitializeNowFunctionPointers(), has happened by this point.
+  ATOMIC_THREAD_FENCE(memory_order_acquire);
+
+  DCHECK_GT(g_qpc_ticks_per_second, 0);
+
+  // If the QPC Value is below the overflow threshold, we proceed with
+  // simple multiply and divide.
+  if (qpc_value < Time::kQPCOverflowThreshold) {
+    return TimeDelta::FromMicroseconds(
+        qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
   }
-
-  bool IsUsingHighResClock() {
-    return ticks_per_second_ != 0;
-  }
-
-  TimeDelta Now() {
-    if (IsUsingHighResClock())
-      return TimeDelta::FromMicroseconds(UnreliableNow());
-
-    // Just fallback to the slower clock.
-    return RolloverProtectedNow();
-  }
-
-  int64 GetQPCDriftMicroseconds() {
-    if (!IsUsingHighResClock())
-      return 0;
-    return abs((UnreliableNow() - ReliableNow()) - skew_);
-  }
-
-  int64 QPCValueToMicroseconds(LONGLONG qpc_value) {
-    if (!ticks_per_second_)
-      return 0;
-    // If the QPC Value is below the overflow threshold, we proceed with
-    // simple multiply and divide.
-    if (qpc_value < Time::kQPCOverflowThreshold)
-      return qpc_value * Time::kMicrosecondsPerSecond / ticks_per_second_;
-    // Otherwise, calculate microseconds in a round about manner to avoid
-    // overflow and precision issues.
-    int64 whole_seconds = qpc_value / ticks_per_second_;
-    int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_);
-    int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
-                         ((leftover_ticks * Time::kMicrosecondsPerSecond) /
-                          ticks_per_second_);
-    return microseconds;
-  }
-
- private:
-  // Get the number of microseconds since boot in an unreliable fashion.
-  int64 UnreliableNow() {
-    LARGE_INTEGER now;
-    QueryPerformanceCounter(&now);
-    return QPCValueToMicroseconds(now.QuadPart);
-  }
-
-  // Get the number of microseconds since boot in a reliable fashion.
-  int64 ReliableNow() {
-    return RolloverProtectedNow().InMicroseconds();
-  }
-
-  int64 ticks_per_second_;  // 0 indicates QPF failed and we're broken.
-  int64 skew_;  // Skew between lo-res and hi-res clocks (for debugging).
-};
-
-static base::LazyInstance<HighResNowSingleton>::Leaky
-    leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER;
-
-HighResNowSingleton* GetHighResNowSingleton() {
-  return leaky_high_res_now_singleton.Pointer();
+  // Otherwise, calculate microseconds in a round about manner to avoid
+  // overflow and precision issues.
+  int64 whole_seconds = qpc_value / g_qpc_ticks_per_second;
+  int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second);
+  return TimeDelta::FromMicroseconds(
+      (whole_seconds * Time::kMicrosecondsPerSecond) +
+      ((leftover_ticks * Time::kMicrosecondsPerSecond) /
+       g_qpc_ticks_per_second));
 }
 
-TimeDelta HighResNowWrapper() {
-  return GetHighResNowSingleton()->Now();
+TimeTicks QPCNow() {
+  LARGE_INTEGER now;
+  QueryPerformanceCounter(&now);
+  return TimeTicks() + QPCValueToTimeDelta(now.QuadPart);
 }
 
-typedef TimeDelta (*NowFunction)(void);
+bool IsBuggyAthlon(const base::CPU& cpu) {
+  // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
+  return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
+}
 
-bool CPUReliablySupportsHighResTime() {
+void InitializeNowFunctionPointers() {
+  LARGE_INTEGER ticks_per_sec = {0};
+  if (!QueryPerformanceFrequency(&ticks_per_sec))
+    ticks_per_sec.QuadPart = 0;
+
+  // If Windows cannot provide a QPC implementation, both Now() and
+  // NowFromSystemTraceTime() must use the low-resolution clock.
+  //
+  // If the QPC implementation is expensive and/or unreliable, Now() will use
+  // the low-resolution clock, but NowFromSystemTraceTime() will use the QPC (in
+  // the hope that it is still useful for tracing purposes). A CPU lacking a
+  // non-stop time counter will cause Windows to provide an alternate QPC
+  // implementation that works, but is expensive to use. Certain Athlon CPUs are
+  // known to make the QPC implementation unreliable.
+  //
+  // Otherwise, both Now functions can use the high-resolution QPC clock. As of
+  // 4 January 2015, ~68% of users fall within this category.
+  NowFunction now_function;
+  NowFunction system_trace_now_function;
   base::CPU cpu;
-  if (!cpu.has_non_stop_time_stamp_counter() ||
-      !GetHighResNowSingleton()->IsUsingHighResClock())
-    return false;
+  if (ticks_per_sec.QuadPart <= 0) {
+    now_function = system_trace_now_function = &RolloverProtectedNow;
+  } else if (!cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) {
+    now_function = &RolloverProtectedNow;
+    system_trace_now_function = &QPCNow;
+  } else {
+    now_function = system_trace_now_function = &QPCNow;
+  }
 
-  if (IsBuggyAthlon(cpu))
-    return false;
-
-  return true;
+  // Threading note 1: In an unlikely race condition, it's possible for two or
+  // more threads to enter InitializeNowFunctionPointers() in parallel. This is
+  // not a problem since all threads should end up writing out the same values
+  // to the global variables.
+  //
+  // Threading note 2: A release fence is placed here to ensure, from the
+  // perspective of other threads using the function pointers, that the
+  // assignment to |g_qpc_ticks_per_second| happens before the function pointers
+  // are changed.
+  g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
+  ATOMIC_THREAD_FENCE(memory_order_release);
+  g_now_function = now_function;
+  g_system_trace_now_function = system_trace_now_function;
 }
 
-TimeDelta InitialNowFunction();
+TimeTicks InitialNowFunction() {
+  InitializeNowFunctionPointers();
+  return g_now_function();
+}
 
-volatile NowFunction now_function = InitialNowFunction;
-
-TimeDelta InitialNowFunction() {
-  if (!CPUReliablySupportsHighResTime()) {
-    InterlockedExchangePointer(
-        reinterpret_cast<void* volatile*>(&now_function),
-        &RolloverProtectedNow);
-    return RolloverProtectedNow();
-  }
-  InterlockedExchangePointer(
-        reinterpret_cast<void* volatile*>(&now_function),
-        &HighResNowWrapper);
-  return HighResNowWrapper();
+TimeTicks InitialSystemTraceNowFunction() {
+  InitializeNowFunctionPointers();
+  return g_system_trace_now_function();
 }
 
 }  // namespace
@@ -491,27 +483,24 @@
 // static
 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
     TickFunctionType ticker) {
-  base::AutoLock locked(rollover_lock);
-  TickFunctionType old = tick_function;
-  tick_function = ticker;
-  rollover_ms = 0;
-  last_seen_now = 0;
+  base::AutoLock locked(g_rollover_lock);
+  TickFunctionType old = g_tick_function;
+  g_tick_function = ticker;
+  g_rollover_ms = 0;
+  g_last_seen_now = 0;
   return old;
 }
 
 // static
 TimeTicks TimeTicks::Now() {
-  return TimeTicks() + now_function();
+  return g_now_function();
 }
 
 // static
-TimeTicks TimeTicks::HighResNow() {
-  return TimeTicks() + HighResNowWrapper();
-}
-
-// static
-bool TimeTicks::IsHighResNowFastAndReliable() {
-  return CPUReliablySupportsHighResTime();
+bool TimeTicks::IsHighResolution() {
+  if (g_now_function == &InitialNowFunction)
+    InitializeNowFunctionPointers();
+  return g_now_function == &QPCNow;
 }
 
 // static
@@ -522,27 +511,17 @@
 
 // static
 TimeTicks TimeTicks::NowFromSystemTraceTime() {
-  return HighResNow();
-}
-
-// static
-int64 TimeTicks::GetQPCDriftMicroseconds() {
-  return GetHighResNowSingleton()->GetQPCDriftMicroseconds();
+  return g_system_trace_now_function();
 }
 
 // static
 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
-  return TimeTicks(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
-}
-
-// static
-bool TimeTicks::IsHighResClockWorking() {
-  return GetHighResNowSingleton()->IsUsingHighResClock();
+  return TimeTicks() + QPCValueToTimeDelta(qpc_value);
 }
 
 // TimeDelta ------------------------------------------------------------------
 
 // static
 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
-  return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
+  return QPCValueToTimeDelta(qpc_value);
 }
diff --git a/time/time_win_unittest.cc b/time/time_win_unittest.cc
index 058dfd7..71cd29e 100644
--- a/time/time_win_unittest.cc
+++ b/time/time_win_unittest.cc
@@ -6,6 +6,10 @@
 #include <mmsystem.h>
 #include <process.h>
 
+#include <cmath>
+#include <limits>
+#include <vector>
+
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -114,7 +118,7 @@
 TEST(TimeTicks, SubMillisecondTimers) {
   // HighResNow doesn't work on some systems.  Since the product still works
   // even if it doesn't work, it makes this entire test questionable.
-  if (!TimeTicks::IsHighResClockWorking())
+  if (!TimeTicks::IsHighResolution())
     return;
 
   const int kRetries = 1000;
@@ -183,7 +187,7 @@
   TestCase cases[] = {
     { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" },
     { TimeTicks::Now, "TimeTicks::Now" },
-    { TimeTicks::HighResNow, "TimeTicks::HighResNow" },
+    { TimeTicks::NowFromSystemTraceTime, "TimeTicks::NowFromSystemTraceTime" },
     { NULL, "" }
   };
 
@@ -207,65 +211,57 @@
   }
 }
 
-// http://crbug.com/396384
-TEST(TimeTicks, DISABLED_Drift) {
-  // If QPC is disabled, this isn't measuring anything.
-  if (!TimeTicks::IsHighResClockWorking())
-    return;
-
-  const int kIterations = 100;
-  int64 total_drift = 0;
-
-  for (int i = 0; i < kIterations; ++i) {
-    int64 drift_microseconds = TimeTicks::GetQPCDriftMicroseconds();
-
-    // Make sure the drift never exceeds our limit.
-    EXPECT_LT(drift_microseconds, 50000);
-
-    // Sleep for a few milliseconds (note that it means 1000 microseconds).
-    // If we check the drift too frequently, it's going to increase
-    // monotonically, making our measurement less realistic.
-    base::PlatformThread::Sleep(
-        base::TimeDelta::FromMilliseconds((i % 2 == 0) ? 1 : 2));
-
-    total_drift += drift_microseconds;
-  }
-
-  // Sanity check. We expect some time drift to occur, especially across
-  // the number of iterations we do.
-  EXPECT_LT(0, total_drift);
-
-  printf("average time drift in microseconds: %lld\n",
-         total_drift / kIterations);
-}
-
-int64 QPCValueToMicrosecondsSafely(LONGLONG qpc_value,
-                                   int64 ticks_per_second) {
-  int64 whole_seconds = qpc_value / ticks_per_second;
-  int64 leftover_ticks = qpc_value % ticks_per_second;
-  int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
-                       ((leftover_ticks * Time::kMicrosecondsPerSecond) /
-                        ticks_per_second);
-  return microseconds;
-}
-
 TEST(TimeTicks, FromQPCValue) {
-  if (!TimeTicks::IsHighResClockWorking())
+  if (!TimeTicks::IsHighResolution())
     return;
+
   LARGE_INTEGER frequency;
-  QueryPerformanceFrequency(&frequency);
-  int64 ticks_per_second = frequency.QuadPart;
-  LONGLONG qpc_value = Time::kQPCOverflowThreshold;
-  TimeTicks expected_value = TimeTicks::FromInternalValue(
-    QPCValueToMicrosecondsSafely(qpc_value + 1, ticks_per_second));
-  EXPECT_EQ(expected_value,
-            TimeTicks::FromQPCValue(qpc_value + 1));
-  expected_value = TimeTicks::FromInternalValue(
-    QPCValueToMicrosecondsSafely(qpc_value, ticks_per_second));
-  EXPECT_EQ(expected_value,
-            TimeTicks::FromQPCValue(qpc_value));
-  expected_value = TimeTicks::FromInternalValue(
-    QPCValueToMicrosecondsSafely(qpc_value - 1, ticks_per_second));
-  EXPECT_EQ(expected_value,
-            TimeTicks::FromQPCValue(qpc_value - 1));
+  ASSERT_TRUE(QueryPerformanceFrequency(&frequency));
+  const int64 ticks_per_second = frequency.QuadPart;
+  ASSERT_GT(ticks_per_second, 0);
+
+  // Generate the tick values to convert, advancing the tick count by varying
+  // amounts.  These values will ensure that both the fast and overflow-safe
+  // conversion logic in FromQPCValue() is tested, and across the entire range
+  // of possible QPC tick values.
+  std::vector<int64> test_cases;
+  test_cases.push_back(0);
+  const int kNumAdvancements = 100;
+  int64 ticks = 0;
+  int64 ticks_increment = 10;
+  for (int i = 0; i < kNumAdvancements; ++i) {
+    test_cases.push_back(ticks);
+    ticks += ticks_increment;
+    ticks_increment = ticks_increment * 6 / 5;
+  }
+  test_cases.push_back(Time::kQPCOverflowThreshold - 1);
+  test_cases.push_back(Time::kQPCOverflowThreshold);
+  test_cases.push_back(Time::kQPCOverflowThreshold + 1);
+  ticks = Time::kQPCOverflowThreshold + 10;
+  ticks_increment = 10;
+  for (int i = 0; i < kNumAdvancements; ++i) {
+    test_cases.push_back(ticks);
+    ticks += ticks_increment;
+    ticks_increment = ticks_increment * 6 / 5;
+  }
+  test_cases.push_back(std::numeric_limits<int64>::max());
+
+  // Test that the conversions using FromQPCValue() match those computed here
+  // using simple floating-point arithmetic.  The floating-point math provides
+  // enough precision to confirm the implementation is correct to the
+  // microsecond for all |test_cases| (though it would be insufficient to
+  // confirm many "very large" tick values which are not being tested here).
+  for (int64 ticks : test_cases) {
+    const double expected_microseconds_since_origin =
+        (static_cast<double>(ticks) * Time::kMicrosecondsPerSecond) /
+            ticks_per_second;
+    const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks);
+    const double converted_microseconds_since_origin =
+        static_cast<double>((converted_value - TimeTicks()).InMicroseconds());
+    EXPECT_NEAR(expected_microseconds_since_origin,
+                converted_microseconds_since_origin,
+                1.0)
+        << "ticks=" << ticks << ", to be converted via logic path: "
+        << (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE");
+  }
 }
diff --git a/values.cc b/values.cc
index b478b62..061b7a1 100644
--- a/values.cc
+++ b/values.cc
@@ -89,6 +89,10 @@
   return new Value(TYPE_NULL);
 }
 
+bool Value::GetAsBinary(const BinaryValue** out_value) const {
+  return false;
+}
+
 bool Value::GetAsBoolean(bool* out_value) const {
   return false;
 }
@@ -319,6 +323,12 @@
   return new BinaryValue(scoped_buffer_copy.Pass(), size);
 }
 
+bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
 BinaryValue* BinaryValue::DeepCopy() const {
   return CreateWithCopiedBuffer(buffer_.get(), size_);
 }
diff --git a/values.h b/values.h
index 4c22f3d..4648283 100644
--- a/values.h
+++ b/values.h
@@ -33,6 +33,7 @@
 
 namespace base {
 
+class BinaryValue;
 class DictionaryValue;
 class FundamentalValue;
 class ListValue;
@@ -85,6 +86,7 @@
   virtual bool GetAsString(std::string* out_value) const;
   virtual bool GetAsString(string16* out_value) const;
   virtual bool GetAsString(const StringValue** out_value) const;
+  virtual bool GetAsBinary(const BinaryValue** out_value) const;
   virtual bool GetAsList(ListValue** out_value);
   virtual bool GetAsList(const ListValue** out_value) const;
   virtual bool GetAsDictionary(DictionaryValue** out_value);
@@ -188,6 +190,7 @@
   const char* GetBuffer() const { return buffer_.get(); }
 
   // Overridden from Value:
+  bool GetAsBinary(const BinaryValue** out_value) const override;
   BinaryValue* DeepCopy() const override;
   bool Equals(const Value* other) const override;
 
diff --git a/values_unittest.cc b/values_unittest.cc
index 296880a..b66730b 100644
--- a/values_unittest.cc
+++ b/values_unittest.cc
@@ -127,6 +127,12 @@
   ASSERT_NE(stack_buffer, binary->GetBuffer());
   ASSERT_EQ(42U, binary->GetSize());
   ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize()));
+
+  // Test overloaded GetAsBinary.
+  Value* narrow_value = binary.get();
+  const BinaryValue* narrow_binary = NULL;
+  ASSERT_TRUE(narrow_value->GetAsBinary(&narrow_binary));
+  EXPECT_EQ(binary.get(), narrow_binary);
 }
 
 TEST(ValuesTest, StringValue) {
diff --git a/win/message_window.cc b/win/message_window.cc
index 57fe64c..0b4b29f 100644
--- a/win/message_window.cc
+++ b/win/message_window.cc
@@ -7,6 +7,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/process/memory.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/win/wrapped_window_proc.h"
 
 const wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow";
@@ -120,6 +121,10 @@
                                            UINT message,
                                            WPARAM wparam,
                                            LPARAM lparam) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 MessageWindow::WindowProc"));
+
   MessageWindow* self = reinterpret_cast<MessageWindow*>(
       GetWindowLongPtr(hwnd, GWLP_USERDATA));