Update from https://crrev.com/317530

TBR=qsr@chromium.org
BUG=461092

Review URL: https://codereview.chromium.org/952893003
diff --git a/BUILD.gn b/BUILD.gn
index e417681..c63d377 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -42,7 +42,6 @@
     "android/jni_android.h",
     "android/jni_array.cc",
     "android/jni_array.h",
-    "android/jni_onload_delegate.h",
     "android/jni_registrar.cc",
     "android/jni_registrar.h",
     "android/jni_string.cc",
@@ -676,6 +675,10 @@
     "trace_event/memory_dump_provider.h",
     "trace_event/process_memory_dump.cc",
     "trace_event/process_memory_dump.h",
+    "trace_event/process_memory_totals.cc",
+    "trace_event/process_memory_totals.h",
+    "trace_event/process_memory_totals_dump_provider.cc",
+    "trace_event/process_memory_totals_dump_provider.h",
     "trace_event/trace_event.h",
     "trace_event/trace_event_android.cc",
     "trace_event/trace_event_argument.cc",
@@ -869,7 +872,7 @@
     ]
 
     # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-    cflags = [ "/wd4267" ]
+    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
     libs = [
       "cfgmgr32.lib",
@@ -1028,10 +1031,8 @@
     configs += [ "//build/config/compiler:optimize_max" ]
   }
 
-  if (is_win) {
-    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-    cflags = [ "/wd4267" ]
-  }
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
 
 source_set("prefs") {
@@ -1335,6 +1336,7 @@
     "timer/timer_unittest.cc",
     "tools_sanity_unittest.cc",
     "trace_event/memory_dump_manager_unittest.cc",
+    "trace_event/process_memory_totals_dump_provider_unittest.cc",
     "trace_event/trace_event_argument_unittest.cc",
     "trace_event/trace_event_memory_unittest.cc",
     "trace_event/trace_event_synthetic_delay_unittest.cc",
@@ -1439,10 +1441,8 @@
     set_sources_assignment_filter(sources_assignment_filter)
   }
 
-  if (is_win) {
-    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-    cflags = [ "/wd4267" ]
-  }
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
 
 if (is_android) {
diff --git a/allocator/BUILD.gn b/allocator/BUILD.gn
index e931b1c..a07a356 100644
--- a/allocator/BUILD.gn
+++ b/allocator/BUILD.gn
@@ -36,7 +36,7 @@
     args = [
       visual_studio_path + "/vc/lib",
       rebase_path("$target_gen_dir/allocator"),
-      cpu_arch,
+      current_cpu,
     ]
   }
 }
diff --git a/android/base_jni_onload.cc b/android/base_jni_onload.cc
index ae64120..c3a65d4 100644
--- a/android/base_jni_onload.cc
+++ b/android/base_jni_onload.cc
@@ -5,59 +5,51 @@
 #include "base/android/base_jni_onload.h"
 
 #include "base/android/jni_android.h"
-#include "base/android/jni_onload_delegate.h"
+#include "base/android/jni_utils.h"
 #include "base/android/library_loader/library_loader_hooks.h"
+#include "base/bind.h"
 
 namespace base {
 namespace android {
 
 namespace {
 
-// The JNIOnLoadDelegate implementation in base.
-class BaseJNIOnLoadDelegate : public JNIOnLoadDelegate {
- public:
-  bool RegisterJNI(JNIEnv* env) override;
-  bool Init() override;
-};
-
-bool BaseJNIOnLoadDelegate::RegisterJNI(JNIEnv* env) {
+bool RegisterJNI(JNIEnv* env) {
   return RegisterLibraryLoaderEntryHook(env);
 }
 
-bool BaseJNIOnLoadDelegate::Init() {
+bool Init() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::InitReplacementClassLoader(env,
+                                            base::android::GetClassLoader(env));
   return true;
 }
 
 }  // namespace
 
 
-bool OnJNIOnLoad(JavaVM* vm,
-                 std::vector<JNIOnLoadDelegate*>* delegates) {
+bool OnJNIOnLoadRegisterJNI(JavaVM* vm,
+                            std::vector<RegisterCallback> callbacks) {
   base::android::InitVM(vm);
   JNIEnv* env = base::android::AttachCurrentThread();
 
-  BaseJNIOnLoadDelegate delegate;
-  delegates->push_back(&delegate);
-  bool ret = true;
-  for (std::vector<JNIOnLoadDelegate*>::reverse_iterator i =
-           delegates->rbegin(); i != delegates->rend(); ++i) {
-    if (!(*i)->RegisterJNI(env)) {
-      ret = false;
-      break;
-    }
+  callbacks.push_back(base::Bind(&RegisterJNI));
+  for (std::vector<RegisterCallback>::reverse_iterator i =
+           callbacks.rbegin(); i != callbacks.rend(); ++i) {
+    if (!i->Run(env))
+      return false;
   }
+  return true;
+}
 
-  if (ret) {
-    for (std::vector<JNIOnLoadDelegate*>::reverse_iterator i =
-             delegates->rbegin(); i != delegates->rend(); ++i) {
-      if (!(*i)->Init()) {
-        ret = false;
-        break;
-      }
-    }
+bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks) {
+  callbacks.push_back(base::Bind(&Init));
+  for (std::vector<InitCallback>::reverse_iterator i =
+           callbacks.rbegin(); i != callbacks.rend(); ++i) {
+    if (!i->Run())
+      return false;
   }
-  delegates->pop_back();
-  return ret;
+  return true;
 }
 
 }  // namespace android
diff --git a/android/base_jni_onload.h b/android/base_jni_onload.h
index f3f05fa..dcc7756 100644
--- a/android/base_jni_onload.h
+++ b/android/base_jni_onload.h
@@ -9,17 +9,22 @@
 #include <vector>
 
 #include "base/base_export.h"
+#include "base/callback.h"
 
 namespace base {
 namespace android {
 
-class JNIOnLoadDelegate;
+// Returns whether JNI registration succeeded. Caller shall put the
+// RegisterCallback into |callbacks| in reverse order.
+typedef base::Callback<bool(JNIEnv*)> RegisterCallback;
+BASE_EXPORT bool OnJNIOnLoadRegisterJNI(
+    JavaVM* vm,
+    std::vector<RegisterCallback> callbacks);
 
-// Returns whether JNI registration and initialization succeeded. Caller shall
-// put the JNIOnLoadDelegate into |delegates| in reverse order. Refer
-// JNIOnLoadDelegate for more information.
-BASE_EXPORT bool OnJNIOnLoad(JavaVM* vm,
-                             std::vector<JNIOnLoadDelegate*>* delegates);
+// Returns whether initialization succeeded. Caller shall put the
+// InitCallback into |callbacks| in reverse order.
+typedef base::Callback<bool(void)> InitCallback;
+BASE_EXPORT bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks);
 
 }  // namespace android
 }  // namespace base
diff --git a/android/java/src/org/chromium/base/ResourceExtractor.java b/android/java/src/org/chromium/base/ResourceExtractor.java
index 9252b4d..d44f2fc 100644
--- a/android/java/src/org/chromium/base/ResourceExtractor.java
+++ b/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -12,6 +12,8 @@
 import android.content.res.AssetManager;
 import android.os.AsyncTask;
 import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.Trace;
 import android.preference.PreferenceManager;
 import android.util.Log;
@@ -57,6 +59,8 @@
     private class ExtractTask extends AsyncTask<Void, Void, Void> {
         private static final int BUFFER_SIZE = 16 * 1024;
 
+        private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>();
+
         public ExtractTask() {
         }
 
@@ -211,6 +215,23 @@
             return null;
         }
 
+        private void onPostExecuteImpl() {
+            for (int i = 0; i < mCompletionCallbacks.size(); i++) {
+                mCompletionCallbacks.get(i).run();
+            }
+            mCompletionCallbacks.clear();
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            beginTraceSection("ResourceExtractor.ExtractTask.onPostExecute");
+            try {
+                onPostExecuteImpl();
+            } finally {
+                endTraceSection();
+            }
+        }
+
         // Looks for a timestamp file on disk that indicates the version of the APK that
         // the resource paks were extracted from. Returns null if a timestamp was found
         // and it indicates that the resources match the current APK. Otherwise returns
@@ -335,6 +356,13 @@
         mContext = context.getApplicationContext();
     }
 
+    /**
+     * Synchronously wait for the resource extraction to be completed.
+     * <p>
+     * This method is bad and you should feel bad for using it.
+     *
+     * @see #addCompletionCallback(Runnable)
+     */
     public void waitForCompletion() {
         if (shouldSkipPakExtraction()) {
             return;
@@ -355,6 +383,35 @@
     }
 
     /**
+     * Adds a callback to be notified upon the completion of resource extraction.
+     * <p>
+     * If the resource task has already completed, the callback will be posted to the UI message
+     * queue.  Otherwise, it will be executed after all the resources have been extracted.
+     * <p>
+     * This must be called on the UI thread.  The callback will also always be executed on
+     * the UI thread.
+     *
+     * @param callback The callback to be enqueued.
+     */
+    public void addCompletionCallback(Runnable callback) {
+        ThreadUtils.assertOnUiThread();
+
+        Handler handler = new Handler(Looper.getMainLooper());
+        if (shouldSkipPakExtraction()) {
+            handler.post(callback);
+            return;
+        }
+
+        assert mExtractTask != null;
+        assert !mExtractTask.isCancelled();
+        if (mExtractTask.getStatus() == AsyncTask.Status.FINISHED) {
+            handler.post(callback);
+        } else {
+            mExtractTask.mCompletionCallbacks.add(callback);
+        }
+    }
+
+    /**
      * This will extract the application pak resources in an
      * AsyncTask. Call waitForCompletion() at the point resources
      * are needed to block until the task completes.
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 23f953c..bbf76cb 100644
--- a/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -1039,7 +1039,7 @@
             mLoadSize = in.readLong();
             mRelroStart = in.readLong();
             mRelroSize = in.readLong();
-            ParcelFileDescriptor fd = in.readFileDescriptor();
+            ParcelFileDescriptor fd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
             // If CreateSharedRelro fails, the OS file descriptor will be -1 and |fd| will be null.
             mRelroFd = (fd == null) ? -1 : fd.detachFd();
         }
diff --git a/android/jni_android.cc b/android/jni_android.cc
index e09c2d5..a2de00a 100644
--- a/android/jni_android.cc
+++ b/android/jni_android.cc
@@ -17,6 +17,8 @@
 using base::android::MethodID;
 using base::android::ScopedJavaLocalRef;
 
+bool g_disable_manual_jni_registration = false;
+
 JavaVM* g_jvm = NULL;
 // Leak the global app context, as it is used from a non-joinable worker thread
 // that may still be running at shutdown. There is no harm in doing this.
@@ -77,6 +79,15 @@
 namespace base {
 namespace android {
 
+bool IsManualJniRegistrationDisabled() {
+  return g_disable_manual_jni_registration;
+}
+
+void DisableManualJniRegistration() {
+  DCHECK(!g_disable_manual_jni_registration);
+  g_disable_manual_jni_registration = true;
+}
+
 JNIEnv* AttachCurrentThread() {
   DCHECK(g_jvm);
   JNIEnv* env = NULL;
diff --git a/android/jni_android.h b/android/jni_android.h
index b5e5526..504eb85 100644
--- a/android/jni_android.h
+++ b/android/jni_android.h
@@ -21,6 +21,13 @@
 // Used to mark symbols to be exported in a shared library's symbol table.
 #define JNI_EXPORT __attribute__ ((visibility("default")))
 
+// Used to disable manual JNI registration in binaries that prefer to use native
+// JNI exports for startup performance. This is not compatible with the crazy
+// linker and so defaults to off. Call DisableManualJniRegistration at the very
+// beginning of JNI_OnLoad to use this.
+BASE_EXPORT bool IsManualJniRegistrationDisabled();
+BASE_EXPORT void DisableManualJniRegistration();
+
 // Contains the registration method information for initializing JNI bindings.
 struct RegistrationMethod {
   const char* name;
diff --git a/android/jni_generator/jni_generator.py b/android/jni_generator/jni_generator.py
index 6e39c13..54fea6b 100755
--- a/android/jni_generator/jni_generator.py
+++ b/android/jni_generator/jni_generator.py
@@ -889,7 +889,7 @@
 
   def GetJNINativeMethodsString(self):
     """Returns the implementation of the array of native methods."""
-    if self.options.native_exports:
+    if self.options.native_exports and not self.options.native_exports_optional:
       return ''
     template = Template("""\
 static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
@@ -922,7 +922,7 @@
     """Returns the code for RegisterNatives."""
     template = Template("""\
 ${REGISTER_NATIVES_SIGNATURE} {
-${CLASSES}
+${EARLY_EXIT}${CLASSES}
 ${NATIVES}
 ${CALLED_BY_NATIVES}
   return true;
@@ -934,9 +934,16 @@
     else:
       signature += ')'
 
+    early_exit = ''
+    if self.options.native_exports_optional:
+      early_exit = """\
+  if (base::android::IsManualJniRegistrationDisabled()) return true;
+"""
+
     natives = self.GetRegisterNativesImplString()
     called_by_natives = self.GetRegisterCalledByNativesImplString()
     values = {'REGISTER_NATIVES_SIGNATURE': signature,
+              'EARLY_EXIT': early_exit,
               'CLASSES': self.GetFindClasses(),
               'NATIVES': natives,
               'CALLED_BY_NATIVES': called_by_natives,
@@ -945,7 +952,7 @@
 
   def GetRegisterNativesImplString(self):
     """Returns the shared implementation for RegisterNatives."""
-    if self.options.native_exports:
+    if self.options.native_exports and not self.options.native_exports_optional:
       return ''
 
     template = Template("""\
@@ -1035,6 +1042,31 @@
         param.name
         for param in called_by_native.params])
 
+  def GetStubName(self, native):
+    """Return the name of the stub function for this native method.
+
+    Args:
+      native: the native dictionary describing the method.
+
+    Returns:
+      A string with the stub function name. For native exports mode this is the
+      Java_* symbol name required by the JVM; otherwise it is just the name of
+      the native method itself.
+    """
+    if self.options.native_exports:
+      template = Template("Java_${JAVA_NAME}_native${NAME}")
+
+      java_name = JniParams.RemapClassName(self.fully_qualified_class)
+      java_name = java_name.replace('_', '_1').replace('/', '_')
+      if native.java_class_name:
+        java_name += '_00024' + native.java_class_name
+
+      values = {'NAME': native.name,
+                'JAVA_NAME': java_name}
+      return template.substitute(values)
+    else:
+      return native.name
+
   def GetForwardDeclaration(self, native):
     template_str = """
 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
@@ -1042,7 +1074,7 @@
     if self.options.native_exports:
       template_str += """
 __attribute__((visibility("default"), alias("${NAME}")))
-${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS});
+${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS});
 """
     template = Template(template_str)
     params_in_call = []
@@ -1050,16 +1082,11 @@
       params_in_call = ['env', 'jcaller']
     params_in_call = ', '.join(params_in_call + [p.name for p in native.params])
 
-    java_name = JniParams.RemapClassName(self.fully_qualified_class)
-    java_name = java_name.replace('_', '_1').replace('/', '_')
-    if native.java_class_name:
-      java_name += '_00024' + native.java_class_name
-
     values = {'RETURN': JavaDataTypeToC(native.return_type),
               'NAME': native.name,
-              'JAVA_NAME': java_name,
               'PARAMS': self.GetParamsInDeclaration(native),
-              'PARAMS_IN_CALL': params_in_call}
+              'PARAMS_IN_CALL': params_in_call,
+              'STUB_NAME': self.GetStubName(native)}
     return template.substitute(values)
 
   def GetNativeMethodStubString(self, native):
@@ -1067,11 +1094,11 @@
     if self.options.native_exports:
       template_str = """\
 __attribute__((visibility("default")))
-${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env,
+${RETURN} ${STUB_NAME}(JNIEnv* env,
     ${PARAMS_IN_DECLARATION}) {"""
     else:
       template_str = """\
-static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
+static ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
     template_str += """
   ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
   CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
@@ -1093,24 +1120,16 @@
     if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
       post_call = '.Release()'
 
-    if self.options.native_exports:
-      java_name = JniParams.RemapClassName(self.fully_qualified_class)
-      java_name = java_name.replace('_', '_1').replace('/', '_')
-      if native.java_class_name:
-        java_name += '_00024' + native.java_class_name
-    else:
-      java_name = ''
-
     values = {
         'RETURN': return_type,
         'OPTIONAL_ERROR_RETURN': optional_error_return,
-        'JAVA_NAME': java_name,
         'NAME': native.name,
         'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
         'PARAM0_NAME': native.params[0].name,
         'P0_TYPE': native.p0_type,
         'PARAMS_IN_CALL': params_in_call,
-        'POST_CALL': post_call
+        'POST_CALL': post_call,
+        'STUB_NAME': self.GetStubName(native),
     }
     return template.substitute(values)
 
@@ -1225,12 +1244,13 @@
     return template.substitute(values)
 
   def GetKMethodArrayEntry(self, native):
-    template = Template("""\
-    { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""")
+    template = Template('    { "native${NAME}", ${JNI_SIGNATURE}, ' +
+                        'reinterpret_cast<void*>(${STUB_NAME}) },')
     values = {'NAME': native.name,
               'JNI_SIGNATURE': JniParams.Signature(native.params,
                                                    native.return_type,
-                                                   True)}
+                                                   True),
+              'STUB_NAME': self.GetStubName(native)}
     return template.substitute(values)
 
   def GetUniqueClasses(self, origin):
@@ -1500,7 +1520,12 @@
   option_parser.add_option('--native_exports', action='store_true',
                            help='Native method registration through .so '
                            'exports.')
+  option_parser.add_option('--native_exports_optional', action='store_true',
+                           help='Support both explicit and native method'
+                           'registration.')
   options, args = option_parser.parse_args(argv)
+  if options.native_exports_optional:
+    options.native_exports = True
   if options.jar_file:
     input_file = ExtractJarInputFile(options.jar_file, options.input_file,
                                      options.output_dir)
diff --git a/android/jni_generator/jni_generator_tests.py b/android/jni_generator/jni_generator_tests.py
index 7e39cda..e29bc0c 100755
--- a/android/jni_generator/jni_generator_tests.py
+++ b/android/jni_generator/jni_generator_tests.py
@@ -43,6 +43,7 @@
     self.cpp = 'cpp'
     self.javap = 'javap'
     self.native_exports = False
+    self.native_exports_optional = False
 
 class TestGenerator(unittest.TestCase):
   def assertObjEquals(self, first, second):
@@ -1019,7 +1020,7 @@
         test_data, 'org/chromium/example/jni_generator/Test', options)
     self.assertGoldenTextEquals(jni_from_java.GetContent())
 
-  def testNativeExportsOption(self):
+  def runNativeExportsOption(self, optional):
     test_data = """
     package org.chromium.example.jni_generator;
 
@@ -1054,9 +1055,18 @@
     options = TestOptions()
     options.jni_init_native_name = 'nativeInitNativeClass'
     options.native_exports = True
+    options.native_exports_optional = optional
     jni_from_java = jni_generator.JNIFromJavaSource(
         test_data, 'org/chromium/example/jni_generator/SampleForTests', options)
-    self.assertGoldenTextEquals(jni_from_java.GetContent())
+    return jni_from_java.GetContent()
+
+  def testNativeExportsOption(self):
+    content = self.runNativeExportsOption(False)
+    self.assertGoldenTextEquals(content)
+
+  def testNativeExportsOptionalOption(self):
+    content = self.runNativeExportsOption(True)
+    self.assertGoldenTextEquals(content)
 
   def testOuterInnerRaises(self):
     test_data = """
diff --git a/android/jni_generator/testNativeExportsOptionalOption.golden b/android/jni_generator/testNativeExportsOptionalOption.golden
new file mode 100644
index 0000000..2a3b172
--- /dev/null
+++ b/android/jni_generator/testNativeExportsOptionalOption.golden
@@ -0,0 +1,283 @@
+// 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.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/SampleForTests
+
+#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
+#define org_chromium_example_jni_generator_SampleForTests_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kSampleForTestsClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
+#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
+
+}  // namespace
+
+extern "C" {
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default"), alias("Init")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller);
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default"), alias("Init")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller);
+
+};  // extern "C"
+
+// Step 2: method stubs.
+
+extern "C" {
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
+    env,
+    jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
+  return native->StaticMethod(env, jcaller, arg1);
+}
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
+    env,
+    jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(env, jcaller, arg1);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
+static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithParam",
+
+"("
+"I"
+")"
+"V",
+      &g_SampleForTests_testMethodWithParam);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(iParam));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
+    0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithParamAndReturn",
+
+"("
+"I"
+")"
+"Ljava/lang/String;",
+      &g_SampleForTests_testMethodWithParamAndReturn);
+
+  jstring ret =
+      static_cast<jstring>(env->CallObjectMethod(obj,
+          method_id, as_jint(iParam)));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
+static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testStaticMethodWithParam",
+
+"("
+"I"
+")"
+"I",
+      &g_SampleForTests_testStaticMethodWithParam);
+
+  jint ret =
+      env->CallStaticIntMethod(SampleForTests_clazz(env),
+          method_id, as_jint(iParam));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
+static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithNoParam",
+
+"("
+")"
+"D",
+      &g_SampleForTests_testMethodWithNoParam);
+
+  jdouble ret =
+      env->CallStaticDoubleMethod(SampleForTests_clazz(env),
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
+    0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testStaticMethodWithNoParam",
+
+"("
+")"
+"Ljava/lang/String;",
+      &g_SampleForTests_testStaticMethodWithNoParam);
+
+  jstring ret =
+static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+};  // extern "C"
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit)
+    },
+};
+
+static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit)
+    },
+};
+
+static const JNINativeMethod kMethodsSampleForTests[] = {
+    { "nativeStaticMethod",
+"("
+"J"
+"I"
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod)
+    },
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod)
+    },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+  if (base::android::IsManualJniRegistrationDisabled()) return true;
+    base::subtle::Release_Store(&g_SampleForTests_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
+
+  const int kMethodsMyOtherInnerClassSize =
+      arraysize(kMethodsMyOtherInnerClass);
+
+  if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
+                           kMethodsMyOtherInnerClass,
+                           kMethodsMyOtherInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyOtherInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+  if (env->RegisterNatives(MyInnerClass_clazz(env),
+                           kMethodsMyInnerClass,
+                           kMethodsMyInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
+
+  if (env->RegisterNatives(SampleForTests_clazz(env),
+                           kMethodsSampleForTests,
+                           kMethodsSampleForTestsSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, SampleForTests_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_1generator_SampleForTests_nativeInitNativeClass(JNIEnv*
+    env, jclass clazz) {
+  return RegisterNativesImpl(env, clazz);
+}
+
+#endif  // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/android/jni_onload_delegate.h b/android/jni_onload_delegate.h
deleted file mode 100644
index ef1b137..0000000
--- a/android/jni_onload_delegate.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ANDROID_JNI_ONLOAD_DELEGATE_H_
-#define BASE_ANDROID_JNI_ONLOAD_DELEGATE_H_
-
-#include <jni.h>
-
-#include "base/base_export.h"
-
-namespace base {
-namespace android {
-
-// This delegate class is used to implement component specific JNI registration
-// and initialization. All methods are called in JNI_OnLoad().
-//
-// Both RegisterJNI() and Init() methods are called if the shared library
-// is loaded by crazy linker that can't find JNI methods without JNI
-// registration, otherwise, only Init() is invoked where dynamic lookup is
-// used to find the JNI methods.
-//
-// It is important to make sure the JNI registration code is only in
-// RegisterJNI(), so it could be stripped out when JNI registration isn't
-// needed.
-class BASE_EXPORT JNIOnLoadDelegate {
- public:
-  virtual ~JNIOnLoadDelegate() {}
-
-  // Returns whether the JNI registration succeeded.
-  virtual bool RegisterJNI(JNIEnv* env) = 0;
-
-  // Returns whether the initialization succeeded. This method is called after
-  // RegisterJNI(), all JNI methods shall ready to be used.
-  virtual bool Init() = 0;
-};
-
-}  // namespace android
-}  // namespace base
-
-#endif  // BASE_ANDROID_JNI_ONLOAD_DELEGATE_H_
diff --git a/base.gyp b/base.gyp
index 8cd5d6a..213e62d 100644
--- a/base.gyp
+++ b/base.gyp
@@ -645,6 +645,7 @@
         'timer/timer_unittest.cc',
         'tools_sanity_unittest.cc',
         'trace_event/memory_dump_manager_unittest.cc',
+        'trace_event/process_memory_totals_dump_provider_unittest.cc',
         'trace_event/trace_event_argument_unittest.cc',
         'trace_event/trace_event_memory_unittest.cc',
         'trace_event/trace_event_synthetic_delay_unittest.cc',
diff --git a/base.gypi b/base.gypi
index 37a8171..b7c33b8 100644
--- a/base.gypi
+++ b/base.gypi
@@ -44,7 +44,6 @@
           'android/jni_android.h',
           'android/jni_array.cc',
           'android/jni_array.h',
-          'android/jni_onload_delegate.h',
           'android/jni_registrar.cc',
           'android/jni_registrar.h',
           'android/jni_string.cc',
@@ -672,6 +671,10 @@
           'trace_event/memory_dump_provider.h',
           'trace_event/process_memory_dump.cc',
           'trace_event/process_memory_dump.h',
+          'trace_event/process_memory_totals.cc',
+          'trace_event/process_memory_totals.h',
+          'trace_event/process_memory_totals_dump_provider.cc',
+          'trace_event/process_memory_totals_dump_provider.h',
           'trace_event/trace_event.h',
           'trace_event/trace_event_android.cc',
           'trace_event/trace_event_argument.cc',
diff --git a/i18n/break_iterator.cc b/i18n/break_iterator.cc
index e3aaa2b..e2ed667 100644
--- a/i18n/break_iterator.cc
+++ b/i18n/break_iterator.cc
@@ -74,7 +74,8 @@
                       static_cast<int32_t>(string_.size()),
                       &status);
     if (U_FAILURE(status)) {
-      NOTREACHED() << "ubrk_open failed";
+      NOTREACHED() << "ubrk_open failed for type " << break_type
+          << " with error " << status;
     }
   }
 
diff --git a/i18n/time_formatting_unittest.cc b/i18n/time_formatting_unittest.cc
index 4739b62..df0c1ed 100644
--- a/i18n/time_formatting_unittest.cc
+++ b/i18n/time_formatting_unittest.cc
@@ -158,11 +158,11 @@
 
   EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatShortDate(time));
   EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time));
-  EXPECT_EQ(ASCIIToUTF16("30/04/2011 15:42:07"),
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07"),
             TimeFormatShortDateAndTime(time));
-  EXPECT_EQ(ASCIIToUTF16("30/04/2011 15:42:07 ") + GetShortTimeZone(),
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(),
             TimeFormatShortDateAndTimeWithTimeZone(time));
-  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 15:42:07"),
+  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"),
             TimeFormatFriendlyDateAndTime(time));
   EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"),
             TimeFormatFriendlyDate(time));
diff --git a/ios/device_util.mm b/ios/device_util.mm
index ff7be36..1234562 100644
--- a/ios/device_util.mm
+++ b/ios/device_util.mm
@@ -13,7 +13,6 @@
 #include <sys/socket.h>
 #include <sys/sysctl.h>
 
-#include "base/ios/ios_util.h"
 #include "base/logging.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/memory/scoped_ptr.h"
diff --git a/ios/device_util_unittest.mm b/ios/device_util_unittest.mm
index 3494e00..82d4217 100644
--- a/ios/device_util_unittest.mm
+++ b/ios/device_util_unittest.mm
@@ -5,7 +5,6 @@
 #import <UIKit/UIKit.h>
 
 #include "base/ios/device_util.h"
-#include "base/ios/ios_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
diff --git a/memory/discardable_memory_android.cc b/memory/discardable_memory_android.cc
index 27b390f..5dcdfdc 100644
--- a/memory/discardable_memory_android.cc
+++ b/memory/discardable_memory_android.cc
@@ -53,8 +53,8 @@
     std::vector<DiscardableMemoryType>* types) {
   const DiscardableMemoryType supported_types[] = {
     DISCARDABLE_MEMORY_TYPE_ASHMEM,
-    DISCARDABLE_MEMORY_TYPE_EMULATED,
-    DISCARDABLE_MEMORY_TYPE_SHMEM
+    DISCARDABLE_MEMORY_TYPE_SHMEM,
+    DISCARDABLE_MEMORY_TYPE_EMULATED
   };
   types->assign(supported_types, supported_types + arraysize(supported_types));
 }
diff --git a/memory/discardable_memory_linux.cc b/memory/discardable_memory_linux.cc
index 977b029..670ad7e 100644
--- a/memory/discardable_memory_linux.cc
+++ b/memory/discardable_memory_linux.cc
@@ -19,8 +19,8 @@
 void DiscardableMemory::GetSupportedTypes(
     std::vector<DiscardableMemoryType>* types) {
   const DiscardableMemoryType supported_types[] = {
-    DISCARDABLE_MEMORY_TYPE_EMULATED,
-    DISCARDABLE_MEMORY_TYPE_SHMEM
+    DISCARDABLE_MEMORY_TYPE_SHMEM,
+    DISCARDABLE_MEMORY_TYPE_EMULATED
   };
   types->assign(supported_types, supported_types + arraysize(supported_types));
 }
diff --git a/memory/discardable_memory_mac.cc b/memory/discardable_memory_mac.cc
index c8669a6..e0096e5 100644
--- a/memory/discardable_memory_mac.cc
+++ b/memory/discardable_memory_mac.cc
@@ -23,8 +23,8 @@
     std::vector<DiscardableMemoryType>* types) {
   const DiscardableMemoryType supported_types[] = {
     DISCARDABLE_MEMORY_TYPE_MACH,
-    DISCARDABLE_MEMORY_TYPE_EMULATED,
-    DISCARDABLE_MEMORY_TYPE_SHMEM
+    DISCARDABLE_MEMORY_TYPE_SHMEM,
+    DISCARDABLE_MEMORY_TYPE_EMULATED
   };
   types->assign(supported_types, supported_types + arraysize(supported_types));
 }
diff --git a/memory/discardable_memory_win.cc b/memory/discardable_memory_win.cc
index 977b029..670ad7e 100644
--- a/memory/discardable_memory_win.cc
+++ b/memory/discardable_memory_win.cc
@@ -19,8 +19,8 @@
 void DiscardableMemory::GetSupportedTypes(
     std::vector<DiscardableMemoryType>* types) {
   const DiscardableMemoryType supported_types[] = {
-    DISCARDABLE_MEMORY_TYPE_EMULATED,
-    DISCARDABLE_MEMORY_TYPE_SHMEM
+    DISCARDABLE_MEMORY_TYPE_SHMEM,
+    DISCARDABLE_MEMORY_TYPE_EMULATED
   };
   types->assign(supported_types, supported_types + arraysize(supported_types));
 }
diff --git a/memory/scoped_ptr_unittest.cc b/memory/scoped_ptr_unittest.cc
index 0887a99..766f444 100644
--- a/memory/scoped_ptr_unittest.cc
+++ b/memory/scoped_ptr_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/strings/stringprintf.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -686,8 +685,11 @@
 // value first.
 TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
   scoped_ptr<int> x(new int);
-  std::stringstream s;
-  s << x;
-  std::string expected = base::StringPrintf("%p", x.get());
-  EXPECT_EQ(expected, s.str());
+  std::stringstream s1;
+  s1 << x;
+
+  std::stringstream s2;
+  s2 << x.get();
+
+  EXPECT_EQ(s2.str(), s1.str());
 }
diff --git a/memory/singleton.h b/memory/singleton.h
index e5e2e3e..e50bdc0 100644
--- a/memory/singleton.h
+++ b/memory/singleton.h
@@ -23,7 +23,6 @@
 #include "base/atomicops.h"
 #include "base/base_export.h"
 #include "base/memory/aligned_memory.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/thread_restrictions.h"
 
 namespace base {
@@ -237,8 +236,6 @@
     // instance_ pointer must acquire visibility over the singleton data.
     base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
     if (value != 0 && value != base::internal::kBeingCreatedMarker) {
-      // See the corresponding HAPPENS_BEFORE below.
-      ANNOTATE_HAPPENS_AFTER(&instance_);
       return reinterpret_cast<Type*>(value);
     }
 
@@ -250,10 +247,6 @@
       // stop right after we do this store.
       Type* newval = Traits::New();
 
-      // This annotation helps race detectors recognize correct lock-less
-      // synchronization between different threads calling get().
-      // See the corresponding HAPPENS_AFTER below and above.
-      ANNOTATE_HAPPENS_BEFORE(&instance_);
       // Releases the visibility over instance_ to the readers.
       base::subtle::Release_Store(
           &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
@@ -267,8 +260,6 @@
     // We hit a race. Wait for the other thread to complete it.
     value = base::internal::WaitForInstance(&instance_);
 
-    // See the corresponding HAPPENS_BEFORE above.
-    ANNOTATE_HAPPENS_AFTER(&instance_);
     return reinterpret_cast<Type*>(value);
   }
 
diff --git a/process/process_win.cc b/process/process_win.cc
index 4e600f9..8e5360b 100644
--- a/process/process_win.cc
+++ b/process/process_win.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
 #include "base/process/kill.h"
 #include "base/win/windows_version.h"
 
@@ -165,7 +166,21 @@
     priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
                        PROCESS_MODE_BACKGROUND_END;
   } else {
-    priority = value ? BELOW_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
+    // Experiment (http://crbug.com/458594) with using IDLE_PRIORITY_CLASS as a
+    // background priority for background renderers (this code path is
+    // technically for more than just the renderers but they're the only use
+    // case in practice and experimenting here direclty is thus easier -- plus
+    // it doesn't really hurt as above we already state our intent of using
+    // PROCESS_MODE_BACKGROUND_BEGIN if available which is essentially
+    // IDLE_PRIORITY_CLASS plus lowered IO priority). Enabled by default in the
+    // asbence of field trials to get coverage on the perf waterfall.
+    DWORD background_priority = IDLE_PRIORITY_CLASS;
+    base::FieldTrial* trial =
+        base::FieldTrialList::Find("BackgroundRendererProcesses");
+    if (trial && trial->group_name() == "AllowBelowNormalFromBrowser")
+      background_priority = BELOW_NORMAL_PRIORITY_CLASS;
+
+    priority = value ? background_priority : NORMAL_PRIORITY_CLASS;
   }
 
   return (::SetPriorityClass(Handle(), priority) != 0);
diff --git a/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
index b6c103d..a104831 100644
--- a/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ b/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -4,19 +4,20 @@
 
 package org.chromium.base.test;
 
-import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
 import android.test.AndroidTestRunner;
 import android.test.InstrumentationTestRunner;
 import android.util.Log;
 
-import junit.framework.Test;
 import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import junit.framework.TestResult;
 
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  *  An Instrumentation test runner that checks SDK level for tests with specific requirements.
  */
@@ -24,40 +25,94 @@
 
     private static final String TAG = "BaseInstrumentationTestRunner";
 
-    @Override
-    protected AndroidTestRunner getAndroidTestRunner() {
-        return new BaseAndroidTestRunner(getContext());
+    /**
+     * An interface for classes that check whether a test case should be skipped.
+     */
+    public interface SkipCheck {
+        /**
+         * Checks whether the given test case should be skipped.
+         *
+         * @param testCase The test case to check.
+         * @return Whether the test case should be skipped.
+         */
+        public boolean shouldSkip(TestCase testCase);
     }
 
     /**
-     *  Skips tests that don't meet the requirements of the current device.
+     * A test result that can skip tests.
      */
-    public class BaseAndroidTestRunner extends AndroidTestRunner {
-        private final Context mContext;
+    public class SkippingTestResult extends TestResult {
 
-        public BaseAndroidTestRunner(Context context) {
-            mContext = context;
+        private final List<SkipCheck> mSkipChecks;
+
+        /**
+         * Creates an instance of SkippingTestResult.
+         */
+        public SkippingTestResult() {
+            mSkipChecks = new ArrayList<SkipCheck>();
+        }
+
+        /**
+         * Adds a check for whether a test should run.
+         *
+         * @param skipCheck The check to add.
+         */
+        public void addSkipCheck(SkipCheck skipCheck) {
+            mSkipChecks.add(skipCheck);
+        }
+
+        private boolean shouldSkip(final TestCase test) {
+            for (SkipCheck s : mSkipChecks) {
+                if (s.shouldSkip(test)) return true;
+            }
+            return false;
         }
 
         @Override
-        public void setTest(Test test) {
-            super.setTest(test);
-            TestSuite revisedTestSuite = new TestSuite();
-            for (TestCase testCase : this.getTestCases()) {
-                Class<?> testClass = testCase.getClass();
-                if (shouldSkip(testClass, testCase)) {
-                    revisedTestSuite.addTest(new SkippedTest(testCase));
-                    Bundle skipResult = new Bundle();
-                    skipResult.putBoolean("test_skipped", true);
-                    sendStatus(0, skipResult);
-                } else {
-                    revisedTestSuite.addTest(testCase);
-                }
-            }
-            super.setTest(revisedTestSuite);
-        }
+        protected void run(final TestCase test) {
+            if (shouldSkip(test)) {
+                startTest(test);
 
-        protected boolean shouldSkip(Class<?> testClass, TestCase testCase) {
+                Bundle skipResult = new Bundle();
+                skipResult.putString("class", test.getClass().getName());
+                skipResult.putString("test", test.getName());
+                skipResult.putBoolean("test_skipped", true);
+                sendStatus(0, skipResult);
+
+                endTest(test);
+            } else {
+                super.run(test);
+            }
+        }
+    }
+
+    @Override
+    protected AndroidTestRunner getAndroidTestRunner() {
+        return new AndroidTestRunner() {
+            @Override
+            protected TestResult createTestResult() {
+                SkippingTestResult r = new SkippingTestResult();
+                r.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+                return r;
+            }
+        };
+    }
+
+    /**
+     * Checks the device's SDK level against any specified minimum requirement.
+     */
+    public static class MinAndroidSdkLevelSkipCheck implements SkipCheck {
+
+        /**
+         * If {@link org.chromium.base.test.util.MinAndroidSdkLevel} is present, checks its value
+         * against the device's SDK level.
+         *
+         * @param testCase The test to check.
+         * @return true if the device's SDK level is below the specified minimum.
+         */
+        @Override
+        public boolean shouldSkip(TestCase testCase) {
+            Class<?> testClass = testCase.getClass();
             if (testClass.isAnnotationPresent(MinAndroidSdkLevel.class)) {
                 MinAndroidSdkLevel v = testClass.getAnnotation(MinAndroidSdkLevel.class);
                 if (Build.VERSION.SDK_INT < v.value()) {
@@ -69,28 +124,6 @@
             }
             return false;
         }
-
-        protected Context getContext() {
-            return mContext;
-        }
     }
 
-    /**
-     *  Replaces a TestCase that should be skipped.
-     */
-    public static class SkippedTest extends TestCase {
-
-        public SkippedTest(TestCase skipped) {
-            super(skipped.getClass().getName() + "#" + skipped.getName());
-        }
-
-        @Override
-        protected void runTest() throws Throwable {
-        }
-
-        @Override
-        public String toString() {
-            return "SKIPPED " + super.toString();
-        }
-    }
 }
diff --git a/test/test_suite.cc b/test/test_suite.cc
index 903e93e..d40dd98 100644
--- a/test/test_suite.cc
+++ b/test/test_suite.cc
@@ -35,6 +35,14 @@
 #endif  // OS_IOS
 #endif  // OS_MACOSX
 
+#if !defined(OS_WIN)
+#include "base/i18n/rtl.h"
+#if !defined(OS_IOS)
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+#endif
+#endif
+
 #if defined(OS_ANDROID)
 #include "base/test/test_support_android.h"
 #endif
@@ -321,6 +329,22 @@
   }
 
   base::i18n::InitializeICU();
+  // On the Mac OS X command line, the default locale is *_POSIX. In Chromium,
+  // the locale is set via an OS X locale API and is never *_POSIX.
+  // Some tests (such as those involving word break iterator) will behave
+  // differently and fail if we use *POSIX locale. Setting it to en_US here
+  // does not affect tests that explicitly overrides the locale for testing.
+  // This can be an issue on all platforms other than Windows.
+  // TODO(jshin): Should we set the locale via an OS X locale API here?
+#if !defined(OS_WIN)
+#if defined(OS_IOS)
+  base::i18n::SetICUDefaultLocale("en_US");
+#else
+  std::string default_locale(uloc_getDefault());
+  if (EndsWith(default_locale, "POSIX", false))
+    base::i18n::SetICUDefaultLocale("en_US");
+#endif
+#endif
 
   CatchMaybeTests();
   ResetCommandLine();
diff --git a/time/time.h b/time/time.h
index 18de085..6d61861 100644
--- a/time/time.h
+++ b/time/time.h
@@ -178,6 +178,14 @@
     return delta_ / a.delta_;
   }
 
+  // Multiplicative computations with floats.
+  TimeDelta multiply_by(double a) const {
+    return TimeDelta(delta_ * a);
+  }
+  TimeDelta divide_by(double a) const {
+    return TimeDelta(delta_ / a);
+  }
+
   // Defined below because it depends on the definition of the other classes.
   Time operator+(Time t) const;
   TimeTicks operator+(TimeTicks t) const;
diff --git a/time/time_unittest.cc b/time/time_unittest.cc
index fdac59d..6387ec7 100644
--- a/time/time_unittest.cc
+++ b/time/time_unittest.cc
@@ -867,6 +867,15 @@
             TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude());
 }
 
+
+TEST(TimeDelta, multiply_by) {
+  double d = 0.5;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000).multiply_by(d));
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000).divide_by(d));
+}
+
 TEST(TimeDeltaLogging, DCheckEqCompiles) {
   DCHECK_EQ(TimeDelta(), TimeDelta());
 }
diff --git a/trace_event/memory_dump_manager.cc b/trace_event/memory_dump_manager.cc
index bf631b3..c8be8f8 100644
--- a/trace_event/memory_dump_manager.cc
+++ b/trace_event/memory_dump_manager.cc
@@ -9,22 +9,15 @@
 #include "base/compiler_specific.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
-
-// TODO(primiano): in a separate CL rename DeleteTraceLogForTesting into
-// something like base::internal::TeardownSingletonForTesting so we don't have
-// to add a new friend to singleton each time.
-class DeleteTraceLogForTesting {
- public:
-  static void Delete() {
-    Singleton<
-        base::trace_event::MemoryDumpManager,
-        LeakySingletonTraits<base::trace_event::MemoryDumpManager>>::OnExit(0);
-  }
-};
+#include "base/trace_event/trace_event_argument.h"
 
 namespace base {
 namespace trace_event {
 
+namespace {
+MemoryDumpManager* g_instance_for_testing = nullptr;
+}
+
 // TODO(primiano): this should be smarter and should do something similar to
 // trace event synthetic delays.
 const char MemoryDumpManager::kTraceCategory[] =
@@ -32,13 +25,16 @@
 
 // static
 MemoryDumpManager* MemoryDumpManager::GetInstance() {
+  if (g_instance_for_testing)
+    return g_instance_for_testing;
+
   return Singleton<MemoryDumpManager,
                    LeakySingletonTraits<MemoryDumpManager>>::get();
 }
 
 // static
-void MemoryDumpManager::DeleteForTesting() {
-  DeleteTraceLogForTesting::Delete();
+void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
+  g_instance_for_testing = instance;
 }
 
 MemoryDumpManager::MemoryDumpManager() : memory_tracing_enabled_(0) {
@@ -96,15 +92,14 @@
 // Creates a dump point for the current process and appends it to the trace.
 void MemoryDumpManager::CreateLocalDumpPoint() {
   AutoLock lock(lock_);
-  // TRACE_EVENT_* macros don't induce scoped_refptr type inference, hence we
-  // need the base ConvertableToTraceFormat and the upcast below. The
-  // alternative would be unnecessarily expensive (double Acquire/Release).
-  scoped_refptr<ConvertableToTraceFormat> pmd(new ProcessMemoryDump());
+  scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump());
 
   for (MemoryDumpProvider* dump_provider : dump_providers_enabled_) {
-    dump_provider->DumpInto(static_cast<ProcessMemoryDump*>(pmd.get()));
+    dump_provider->DumpInto(pmd.get());
   }
 
+  scoped_refptr<TracedValue> value(new TracedValue());
+  pmd->AsValueInto(value.get());
   // TODO(primiano): add the dump point to the trace at this point.
 }
 
diff --git a/trace_event/memory_dump_manager.h b/trace_event/memory_dump_manager.h
index fbc71d5..1a22e61 100644
--- a/trace_event/memory_dump_manager.h
+++ b/trace_event/memory_dump_manager.h
@@ -50,17 +50,17 @@
   void OnTraceLogDisabled() override;
 
  private:
+  friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
   friend struct DefaultSingletonTraits<MemoryDumpManager>;
   friend class MemoryDumpManagerTest;
 
   static const char kTraceCategory[];
 
+  static void SetInstanceForTesting(MemoryDumpManager* instance);
+
   MemoryDumpManager();
   virtual ~MemoryDumpManager();
 
-  // Tears down the singleton instance.
-  static void DeleteForTesting();
-
   // Broadcasts the dump requests to the other processes.
   void BroadcastDumpRequest();
 
diff --git a/trace_event/memory_dump_manager_unittest.cc b/trace_event/memory_dump_manager_unittest.cc
index b5337e9..1ba73e6 100644
--- a/trace_event/memory_dump_manager_unittest.cc
+++ b/trace_event/memory_dump_manager_unittest.cc
@@ -17,14 +17,16 @@
 class MemoryDumpManagerTest : public testing::Test {
  public:
   void SetUp() override {
+    mdm_.reset(new MemoryDumpManager());
+    MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+    ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
     MemoryDumpManager::GetInstance()->Initialize();
-    mdm_ = MemoryDumpManager::GetInstance();
   }
 
   void TearDown() override {
-    MemoryDumpManager::DeleteForTesting();
+    MemoryDumpManager::SetInstanceForTesting(nullptr);
+    mdm_.reset();
     TraceLog::DeleteForTesting();
-    mdm_ = NULL;
   }
 
  protected:
@@ -37,7 +39,7 @@
 
   void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
 
-  MemoryDumpManager* mdm_;
+  scoped_ptr<MemoryDumpManager> mdm_;
 
  private:
   // We want our singleton torn down after each test.
diff --git a/trace_event/process_memory_dump.cc b/trace_event/process_memory_dump.cc
index 0a3e096..6da9132 100644
--- a/trace_event/process_memory_dump.cc
+++ b/trace_event/process_memory_dump.cc
@@ -4,25 +4,25 @@
 
 #include "base/trace_event/process_memory_dump.h"
 
-#include "base/json/json_writer.h"
-#include "base/values.h"
+#include "base/trace_event/process_memory_totals.h"
+#include "base/trace_event/trace_event_argument.h"
 
 namespace base {
 namespace trace_event {
 
-ProcessMemoryDump::ProcessMemoryDump() {
+ProcessMemoryDump::ProcessMemoryDump() : has_process_totals_(false) {
 }
 
 ProcessMemoryDump::~ProcessMemoryDump() {
 }
 
-void ProcessMemoryDump::AppendAsTraceFormat(std::string* out) const {
-  // Build up the [dumper name] -> [serialized snapshot] JSON dictionary.
-  DictionaryValue dict;
-  std::string json_dict;
-  // TODO(primiano): this will append here the actual dumps from the dumpers.
-  base::JSONWriter::Write(&dict, &json_dict);
-  *out += json_dict;
+void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
+  // Build up the [dumper name] -> [value] dictionary.
+  if (has_process_totals_) {
+    value->BeginDictionary("process_totals");
+    process_totals_.AsValueInto(value);
+    value->EndDictionary();
+  }
 }
 
 }  // namespace trace_event
diff --git a/trace_event/process_memory_dump.h b/trace_event/process_memory_dump.h
index ae42987..f70537b 100644
--- a/trace_event/process_memory_dump.h
+++ b/trace_event/process_memory_dump.h
@@ -6,27 +6,34 @@
 #define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
 
 #include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/process_memory_totals.h"
 
 namespace base {
 namespace trace_event {
 
-// A container which holds the dumps produced by the MemoryDumpProvider(s)
-// for a specific process. ProcessMemoryDump is as a strongly typed container
-// which enforces the data model for each memory dump point.
-// At trace generation time (i.e. when AppendAsTraceFormat is called) the
-// ProcessMemoryDump will compose a key-value dictionary of the various dumps
-// obtained during at trace dump point time.
-class BASE_EXPORT ProcessMemoryDump : public ConvertableToTraceFormat {
+class ConvertableToTraceFormat;
+
+// ProcessMemoryDump is as a strongly typed container which enforces the data
+// model for each memory dump point and holds the dumps produced by the
+// MemoryDumpProvider(s) for a specific process.
+// At trace generation time (i.e. when AsValue() is called), ProcessMemoryDump
+// will compose a key-value dictionary of the various dumps obtained at trace
+// dump point time.
+class BASE_EXPORT ProcessMemoryDump {
  public:
   ProcessMemoryDump();
+  ~ProcessMemoryDump();
 
-  // ConvertableToTraceFormat implementation.
-  void AppendAsTraceFormat(std::string* out) const override;
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  ProcessMemoryTotals* process_totals() { return &process_totals_; }
+  bool has_process_totals() const { return has_process_totals_; }
+  void set_has_process_totals() { has_process_totals_ = true; }
 
  private:
-  ~ProcessMemoryDump() override;
+  ProcessMemoryTotals process_totals_;
+  bool has_process_totals_;
 
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
 };
diff --git a/trace_event/process_memory_totals.cc b/trace_event/process_memory_totals.cc
new file mode 100644
index 0000000..41ad788
--- /dev/null
+++ b/trace_event/process_memory_totals.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals.h"
+
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
+  value->SetDouble("resident_set_bytes", resident_set_bytes_);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/trace_event/process_memory_totals.h b/trace_event/process_memory_totals.h
new file mode 100644
index 0000000..1c99152
--- /dev/null
+++ b/trace_event/process_memory_totals.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotals {
+ public:
+  ProcessMemoryTotals() {}
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  uint64 resident_set_bytes() const { return resident_set_bytes_; }
+  void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
+
+ private:
+  uint64 resident_set_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
diff --git a/trace_event/process_memory_totals_dump_provider.cc b/trace_event/process_memory_totals_dump_provider.cc
new file mode 100644
index 0000000..cda0ff1
--- /dev/null
+++ b/trace_event/process_memory_totals_dump_provider.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+uint64 ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+namespace {
+ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
+#else
+  return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle(), NULL);
+#endif
+}
+}  // namespace
+
+// static
+ProcessMemoryTotalsDumpProvider*
+ProcessMemoryTotalsDumpProvider::GetInstance() {
+  return Singleton<
+      ProcessMemoryTotalsDumpProvider,
+      LeakySingletonTraits<ProcessMemoryTotalsDumpProvider>>::get();
+}
+
+ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider()
+    : process_metrics_(CreateProcessMetricsForCurrentProcess()) {
+}
+
+ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+void ProcessMemoryTotalsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+  const uint64 rss_bytes = rss_bytes_for_testing
+                               ? rss_bytes_for_testing
+                               : process_metrics_->GetWorkingSetSize();
+  pmd->process_totals()->set_resident_set_bytes(rss_bytes);
+  pmd->set_has_process_totals();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/trace_event/process_memory_totals_dump_provider.h b/trace_event/process_memory_totals_dump_provider.h
new file mode 100644
index 0000000..45917a8
--- /dev/null
+++ b/trace_event/process_memory_totals_dump_provider.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+
+class ProcessMetrics;
+
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotalsDumpProvider : public MemoryDumpProvider {
+ public:
+  static ProcessMemoryTotalsDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  void DumpInto(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
+  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryTotalsDumpProviderTest, DumpRSS);
+
+  static uint64 rss_bytes_for_testing;
+
+  ProcessMemoryTotalsDumpProvider();
+  ~ProcessMemoryTotalsDumpProvider() override;
+
+  scoped_ptr<ProcessMetrics> process_metrics_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotalsDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
diff --git a/trace_event/process_memory_totals_dump_provider_unittest.cc b/trace_event/process_memory_totals_dump_provider_unittest.cc
new file mode 100644
index 0000000..4a60036
--- /dev/null
+++ b/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
+  auto mdptp = ProcessMemoryTotalsDumpProvider::GetInstance();
+  scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump());
+  scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump());
+
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
+  mdptp->DumpInto(pmd_before.get());
+
+  // Pretend that the RSS of the process increased of +1M.
+  const size_t kAllocSize = 1048576;
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
+
+  mdptp->DumpInto(pmd_after.get());
+
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+  ASSERT_TRUE(pmd_before->has_process_totals());
+  ASSERT_TRUE(pmd_after->has_process_totals());
+
+  const uint64 rss_before = pmd_before->process_totals()->resident_set_bytes();
+  const uint64 rss_after = pmd_after->process_totals()->resident_set_bytes();
+
+  EXPECT_NE(0U, rss_before);
+  EXPECT_NE(0U, rss_after);
+
+  EXPECT_EQ(rss_after - rss_before, kAllocSize);
+}
+
+}  // namespace trace_Event
+}  // namespace base
diff --git a/trace_event/trace_event_synthetic_delay.cc b/trace_event/trace_event_synthetic_delay.cc
index 4b957c3..bad79cc 100644
--- a/trace_event/trace_event_synthetic_delay.cc
+++ b/trace_event/trace_event_synthetic_delay.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/memory/singleton.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/trace_event/trace_event_synthetic_delay.h"
 
 namespace {
diff --git a/version.cc b/version.cc
index 6318b35..933356e 100644
--- a/version.cc
+++ b/version.cc
@@ -31,6 +31,8 @@
 
   for (std::vector<std::string>::const_iterator it = numbers.begin();
        it != numbers.end(); ++it) {
+    if (StartsWithASCII(*it, "+", false))
+      return false;
     int num;
     if (!StringToInt(*it, &num))
       return false;
@@ -42,8 +44,8 @@
     if (num > max)
       return false;
 
-    // This throws out things like +3, or 032.
-    if (IntToString(num) != *it)
+    // This throws out leading zeros for the first item only.
+    if (it == numbers.begin() && IntToString(num) != *it)
       return false;
 
     parsed->push_back(static_cast<uint16>(num));
diff --git a/version_unittest.cc b/version_unittest.cc
index 3119c39..46d8255 100644
--- a/version_unittest.cc
+++ b/version_unittest.cc
@@ -41,16 +41,22 @@
     {".", 0, false},
     {" . ", 0, false},
     {"0", 1, true},
+    {"0.", 0, false},
     {"0.0", 2, true},
     {"65537.0", 0, false},
     {"-1.0", 0, false},
     {"1.-1.0", 0, false},
+    {"1,--1.0", 0, false},
     {"+1.0", 0, false},
     {"1.+1.0", 0, false},
+    {"1+1.0", 0, false},
+    {"++1.0", 0, false},
     {"1.0a", 0, false},
     {"1.2.3.4.5.6.7.8.9.0", 10, true},
     {"02.1", 0, false},
+    {"0.01", 2, true},
     {"f.1", 0, false},
+    {"15.007.20011", 3, true},
   };
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
@@ -77,6 +83,7 @@
     {"1.1", "1.0.1", 1},
     {"1.0.0", "1.0", 0},
     {"1.0.3", "1.0.20", -1},
+    {"11.0.10", "15.007.20011", -1},
   };
   for (size_t i = 0; i < arraysize(cases); ++i) {
     Version lhs(cases[i].lhs);
diff --git a/win/pe_image.cc b/win/pe_image.cc
index 572b4d9..e226b6a 100644
--- a/win/pe_image.cc
+++ b/win/pe_image.cc
@@ -20,6 +20,9 @@
 
 namespace {
 
+  // PdbInfo Signature
+  const DWORD kPdbInfoSignature = 'SDSR';
+
   // Compare two strings byte by byte on an unsigned basis.
   //   if s1 == s2, return 0
   //   if s1 < s2, return negative
@@ -35,6 +38,12 @@
             *reinterpret_cast<const unsigned char*>(s2));
   }
 
+  struct PdbInfo {
+    DWORD Signature;
+    GUID Guid;
+    DWORD Age;
+    char PdbFileName[1];
+  };
 }  // namespace
 
 // Callback used to enumerate imports. See EnumImportChunksFunction.
@@ -142,6 +151,36 @@
   return ret;
 }
 
+bool PEImage::GetDebugId(LPGUID guid, LPDWORD age) const {
+  if (NULL == guid || NULL == age) {
+    return false;
+  }
+
+  DWORD debug_directory_size =
+      GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);
+  PIMAGE_DEBUG_DIRECTORY debug_directory =
+      reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(
+      GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
+
+  size_t directory_count =
+      debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY);
+
+  for (size_t index = 0; index < directory_count; ++index) {
+    if (debug_directory[index].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
+      PdbInfo* pdb_info = reinterpret_cast<PdbInfo*>(
+          RVAToAddr(debug_directory[index].AddressOfRawData));
+      if (pdb_info->Signature != kPdbInfoSignature) {
+        // Unsupported PdbInfo signature
+        return false;
+      }
+      *guid = pdb_info->Guid;
+      *age = pdb_info->Age;
+      return true;
+    }
+  }
+  return false;
+}
+
 PDWORD PEImage::GetExportEntry(LPCSTR name) const {
   PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
 
diff --git a/win/pe_image.h b/win/pe_image.h
index dde1b48..5cef537 100644
--- a/win/pe_image.h
+++ b/win/pe_image.h
@@ -132,6 +132,9 @@
   // Returns the exports directory.
   PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
 
+  // Returns the debug id (guid+age).
+  bool GetDebugId(LPGUID guid, LPDWORD age) const;
+
   // Returns a given export entry.
   // Use: e = image.GetExportEntry(f);
   // Pre: 'f' is either a zero terminated string or ordinal
diff --git a/win/pe_image_unittest.cc b/win/pe_image_unittest.cc
index 238c924..af4209b 100644
--- a/win/pe_image_unittest.cc
+++ b/win/pe_image_unittest.cc
@@ -267,5 +267,21 @@
   FreeLibrary(module);
 }
 
+// Test that we can get debug id out of a module.
+TEST(PEImageTest, GetDebugId) {
+  HMODULE module = LoadLibrary(L"advapi32.dll");
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  GUID guid = {0};
+  DWORD age = 0;
+  EXPECT_TRUE(pe.GetDebugId(&guid, &age));
+
+  GUID empty_guid = {0};
+  EXPECT_TRUE(!IsEqualGUID(empty_guid, guid));
+  EXPECT_NE(0U, age);
+  FreeLibrary(module);
+}
+
 }  // namespace win
 }  // namespace base